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> |