Dbms pipe

DBMS_PIPE - Voor intersessie comminicatie

De DBMS_PIPE package voorziet in een "non-secure" mechanisme voor intersessie messaging.

 

Het wordt als "non-secure" gezien omdat boodschappen uit de pipe verloren kunnen gaan als de instance crashed of uit de lucht gaat voordat de boodschap is verwerkt. Advanced Queus is op argumenten een beter mechanisme dan "secure messaging" en als meer flexibiliteit wordt verlangt.

Er zijn 2 soorten pipes:

  • Implicit Pipes - Deze worden automatisch gecreëerd als een boodschap wordt verstuurd met een onbekende pipename, gebruik makend van de SEND_MESSAGE function. Implicit pipes verdwijnen als ze leeg zijn.
  • Explicit Pipes - Deze worden gecreëerd gebruik makend van de CREATE_PIPE function. Explicitly gecreëerde pipes moeten verwijderd worden gebruik makend van de REMOVE_PIPE function.

Er zijn 2 beveiligingsniveau' s voor pipes:

  • Public Pipes - Deze zijn voor iedere user toegankelijk met EXECUTE privilege op de DBMS_PIPE package. Implicit pipes zijn altijd public, maar ze kunnen ook explicitly aangeroepen worden middels de CREATE_PIPE function met de private parameter op FALSE gezet.
  • Private Pipes - Deze zijn alleen toegankelijk door sessies met het zelfde ownerid als de gene die de pipe heeft gecreëerd, stored programs die eigenaar zijn van degene die de pipe heeft gecreëerd of door users die zijn  geconnect als SYSDBA.

Het volgende voorbeeld gebruikte de CREATE_PIPE function om explicit public and private pipes te creëren. De view V$DB_PIPES laat informatie zien over deze pipes.

 

DECLARE
  l_result  INTEGER;
BEGIN
  -- Explicit public pipe.
  l_result := DBMS_PIPE.create_pipe(pipename => 'explicit_public_pipe',
                                    private  => FALSE);
 
  -- Explicit private pipe.
  l_result := DBMS_PIPE.create_pipe(pipename => 'explicit_private_pipe');
END;
/
 
PL/SQL procedure successfully completed.
 
COLUMN name FORMAT A30
SELECT * FROM v$db_pipes;
 
   OWNERID NAME                           TYPE     PIPE_SIZE
---------- ------------------------------ ------- ----------
        55 EXPLICIT_PRIVATE_PIPE          PRIVATE        358
           EXPLICIT_PUBLIC_PIPE           PUBLIC         357
 
2 rows selected.
 
SQL>

Het volgende voorbeeld gebruikt de function REMOVE_PIPE function om de zojuist gecreëerde pipe te verwijderen.

 

DECLARE
  l_result  INTEGER;
BEGIN
  -- Explicit public pipe.
  l_result := DBMS_PIPE.remove_pipe(pipename => 'explicit_public_pipe');
 
  -- Explicit private pipe.
  l_result := DBMS_PIPE.remove_pipe(pipename => 'explicit_private_pipe');
END;
/
 
PL/SQL procedure successfully completed.
 
COLUMN name FORMAT A30
SELECT * FROM v$db_pipes;
 
no rows selected
 
SQL>

De boodschappen worden ingepakt, een variabele per keer, in een buffer gebruik makend van de procedure PACK_MESSAGE. Als de boodschap is verwerkt wordt het verzonden gebruik makend van de SEND_MESSAGE function. Boodschappen worden ontvangen gebruik makend van de RECEIVE_MESSAGE function en uitgepakt, een variabele per keer, gebruik makend van de UNPACK_MESSAGE procedure. De volgende code creëert een package (message_api) dat 2 procedures bevat(send and receive) dat het mogelijk maakt dat boodschappen via een public pipe te zenden en ontvangen.

 

CREATE OR REPLACE PACKAGE message_api AS
  PROCEDURE send (p_number  IN  NUMBER,
                  p_text    IN  VARCHAR2,
                  p_date    IN  DATE DEFAULT SYSDATE);
  PROCEDURE receive;
END message_api;
/
SHOW ERRORS
 
 
CREATE OR REPLACE PACKAGE BODY message_api AS
  PROCEDURE send (p_number  IN  NUMBER,
                  p_text    IN  VARCHAR2,
                  p_date    IN  DATE DEFAULT SYSDATE) AS
    l_status  NUMBER;
  BEGIN
    DBMS_PIPE.pack_message(p_number);
    DBMS_PIPE.pack_message(p_text);
    DBMS_PIPE.pack_message(p_date);
 
    l_status := DBMS_PIPE.send_message('message_pipe');
    IF l_status != 0 THEN
      RAISE_APPLICATION_ERROR(-20001, 'message_pipe error');
    END IF;
  END;
  
  PROCEDURE receive AS
    l_result  INTEGER;
    l_number  NUMBER;
    l_text    VARCHAR2(32767);
    l_date    DATE;
  BEGIN
    l_result := DBMS_PIPE.receive_message (
                  pipename => 'message_pipe',
                  timeout  => DBMS_PIPE.maxwait);
    
    IF l_result = 0 THEN
      -- Message received successfully.
      DBMS_PIPE.unpack_message(l_number);
      DBMS_PIPE.unpack_message(l_text);
      DBMS_PIPE.unpack_message(l_date);
      
      DBMS_OUTPUT.put_line('l_number: ' || l_number);
      DBMS_OUTPUT.put_line('l_text  : ' || l_text);
      DBMS_OUTPUT.put_line('l_date  : ' || l_date);
    ELSE
      RAISE_APPLICATION_ERROR(-20002, 'message_api.receive was unsuccessful. Return result: ' || l_result);
    END IF;              
  END receive;
END message_api;
/
SHOW ERRORS

Om de package te testen, run onderstaande code in 1 sessie. De sessie lijkt te hangen, wachtend op  een boodschap die van de pipe gelezen kan worden.

 

CONN test/test
SET SERVEROUTPUT ON
EXEC message_api.receive;

In een andere sessie, run deze code om een boodschap te sturen.

 

CONN test/test
BEGIN
  message_api.send(p_number => 12345,
                   p_text   => 'Dit is een test',
                   p_date   => SYSDATE);
END;
/

De procedure aanroep in de eerste sessie komt gelijk terug met het bericht als onder.

 

SQL> CONN test/test
Connected.
SQL> SET SERVEROUTPUT ON
SQL> EXEC message_api.receive;
l_number: 12345
l_text  : Dit is een test.
l_date  : 01-OCT-2009 16:10:03
 
PL/SQL procedure successfully completed.
 
SQL>
 

Advertentie

>

Poll

Voorkeur
 

Wie is er aanwezig

We hebben 306 gasten online