home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 February / PCWK0296.iso / po7_win / db / rdbms71 / dbmsalrt.sql < prev    next >
Encoding:
Text File  |  1994-08-07  |  13.8 KB  |  311 lines

  1. rem 
  2. rem $Header: dbmsalrt.sql 7010300.1 94/02/24 18:25:52 snataraj Generic<base> $ 
  3. rem 
  4. Rem  Copyright (c) 1991 by Oracle Corporation 
  5. Rem    NAME
  6. Rem     dbmsalrt.sql - Blocking implementation of DBMS "alerts"
  7. Rem    DESCRIPTION
  8. Rem     Routines to wait-for, and signal, a named event.  The waiting
  9. Rem     session will block in the database until the event occurs, or until
  10. Rem     a timeout expires.  The implementation avoids polling except when
  11. Rem     running in parallel server mode.
  12. Rem    RETURNS
  13. Rem 
  14. Rem    NOTES
  15. Rem      The procedural option is needed to use this facility.
  16. Rem
  17. Rem    MODIFIED   (MM/DD/YY)
  18. Rem     adowning   02/02/94 -  split file into public / private binary files
  19. Rem     mmoore     03/17/93 -  merge changes from branch 1.6.312.1 
  20. Rem     mmoore     03/11/92 - #(153818) fix looping in signal upon cleanup
  21. Rem     rkooi      12/03/92 - #141803, improve some comments 
  22. Rem     rkooi      11/25/92 -  allow signalling and waiting in same session 
  23. Rem     rkooi      11/17/92 -  pipe cleanup bug 
  24. Rem     rkooi      11/12/92 -  don't call removeall from signal
  25. Rem     rkooi      08/12/92 -  surface removeall function 
  26. Rem     rkooi      06/05/92 -  Creation 
  27. REM 
  28.  
  29. create or replace package dbms_alert is
  30.  
  31.   ------------
  32.   --  OVERVIEW
  33.   --
  34.   --  This package provides support for the asynchronous (as opposed to
  35.   --  polling) notification of database events.  By appropriate use of
  36.   --  this package and database triggers, an application can cause itself
  37.   --  to be notified whenever values of interest in the database are
  38.   --  changed.  
  39.   --
  40.   --  For example, suppose a graphics tool is displaying a graph of some
  41.   --  data from a database table.  The graphics tool can, after reading and
  42.   --  graphing the data, wait on a database alert ('dbms_alert.waitone')
  43.   --  covering the data just read.  The tool will automatically wake up when
  44.   --  the data is changed by any other user.  All that is required is that a
  45.   --  trigger be placed on the database table which then performs a signal
  46.   --  ('dbms_alert.signal') whenever the trigger is fired.
  47.   --
  48.   --  Alerts are transaction based.  This means that the waiting session
  49.   --  does not get alerted until the transaction signalling the alert commits.
  50.   --
  51.   --  There can be any number of concurrent signallers of a given alert, and
  52.   --  there can be any number of concurrent waiters on a given alert.
  53.   --
  54.   --  A waiting application will be blocked in the database and cannot do
  55.   --  any other work.
  56.   --  
  57.   --  Most of the calls in the package, except for 'signal', do commits.
  58.   --
  59.  
  60.   -----------
  61.   --  EXAMPLE
  62.   --
  63.   --  Suppose the application wishes to graph average salaries, say by
  64.   --  department, for all employees.  So the application needs to know
  65.   --  whenever 'emp' is changed.  The application would look like this:
  66.   --
  67.   --      dbms_alert.register('emp_table_alert');  
  68.   --    readagain:
  69.   --      <read the emp table and graph it>
  70.   --      dbms_alert.waitone('emp_table_alert', :message, :status);
  71.   --      if status = 0 then goto readagain; else <error condition>
  72.   --
  73.   --  The 'emp' table would have a trigger similar to the following:
  74.   --
  75.   --    create trigger emptrig after insert or update or delete on emp
  76.   --    begin
  77.   --      dbms_alert.signal('emp_table_alert', 'message_text');
  78.   --    end;
  79.   --
  80.   --  When the application is no longer interested in the alert, it does
  81.   --    dbms_alert.remove('emp_table_alert');
  82.   --  This is important since it reduces the amount of work required by
  83.   --  the alert signaller.
  84.   --
  85.   --  If a session exits (or dies) while there exist registered alerts,
  86.   --  they will eventually be cleaned up by future users of this package.
  87.   --
  88.   --  The above example guarantees that the application will always see
  89.   --  the latest data, although it may not see every intermediate value.
  90.  
  91.  
  92.   --------------
  93.   --  VARIATIONS
  94.   --
  95.   --  The application can register for multiple events and can then wait for
  96.   --  any of them to occur using the 'waitany' call.
  97.   --
  98.   --  An application can also supply an optional 'timeout' parameter to the
  99.   --  'waitone' or 'waitany' calls.  A 'timeout' of 0 returns immediately
  100.   --  if there is no pending alert.
  101.   --
  102.   --  The signalling session can optionally pass a message which will be
  103.   --  received by the waiting session.
  104.   --
  105.   --  Alerts may be signalled more often than the corresponding application
  106.   --  'wait' calls.  In such cases the older alerts are discaded.  The 
  107.   --  application always gets the latest alert (based on transaction commit 
  108.   --  times).
  109.   -- 
  110.   --  If the application does not require transaction based alerts, then the 
  111.   --  'dbms_pipe' package may provide a useful alternative
  112.   --
  113.   --  If the transaction is rolled back after the call to 'dbms_alert.signal',
  114.   --  no alert will occur.
  115.   -- 
  116.   --  It is possible to receive an alert, read the data, and find that no
  117.   --  data has changed.  This is because the data changed after the *prior*
  118.   --  alert, but before the data was read for that *prior* alert.
  119.  
  120.  
  121.   --------------------------
  122.   --  IMPLEMENTATION DETAILS
  123.   --
  124.   --  In most cases the implementation is event-driven, i.e., there are no
  125.   --  polling loops.  There are two cases where polling loops can occur:
  126.   --
  127.   --    1) Parallel mode.  If your database is running parallel mode then
  128.   --       a polling loop is required to check for alerts from another
  129.   --       instance.  The polling loop defaults to one second and is settable
  130.   --       by the 'set_defaults' call.
  131.   --    2) Waitany call.  If you use the 'waitany' call, and a signalling 
  132.   --       session does a signal but does not commit within one second of the
  133.   --       signal, then a polling loop is required so that this uncommitted
  134.   --       alert does not camouflage other alerts.  The polling loop begins
  135.   --       at a one second interval and exponentially backs off to 30 second
  136.   --       intervals.
  137.   --  
  138.   --  This package uses the dbms_lock package (for synchronization between
  139.   --  signallers and waiters) and the dbms_pipe package (for asynchronous
  140.   --  event dispatching).
  141.  
  142.   -------------------------------------------------------
  143.   --  INTERACTION WITH MULTI-THREADED AND PARALLEL SERVER
  144.   --
  145.   --  When running with the parallel server AND multi-threaded server, a
  146.   --  multi-threaded (dispatcher) "shared server" will be bound to a
  147.   --  session (and therefore not shareable) during the time a session has
  148.   --  any alerts "registered", OR from the time a session "signals" an
  149.   --  alert until the time the session commits.  Therefore, applications
  150.   --  which register for alerts should use "dedicated servers" rather than
  151.   --  connecting through the dispatcher (to a "shared server") since
  152.   --  registration typically lasts for a long time, and applications which
  153.   --  cause "signals" should have relatively short transactions so as not
  154.   --  to tie up "shared servers" for too long.
  155.  
  156.   ------------
  157.   --  SECURITY
  158.   --
  159.   --  Security on this package may be controlled by granting execute on 
  160.   --  this package to just those users or roles that you trust.  You may
  161.   --  wish to write a cover package on top of this one which restricts
  162.   --  the alertnames used.  Execute privilege on this cover package can
  163.   --  then be granted rather than on this package.    
  164.  
  165.  
  166.   -------------
  167.   --  RESOURCES
  168.   --
  169.   --  This package uses one database pipe and two locks for each alert a 
  170.   --  session has registered.
  171.  
  172.  
  173.   ---------------------
  174.   --  SPECIAL CONSTANTS
  175.   --
  176.   maxwait constant integer :=  86400000; -- 1000 days 
  177.   --  The maximum time to wait for an alert (essentially forever).
  178.  
  179.  
  180.   ----------------------------
  181.   --  PROCEDURES AND FUNCTIONS
  182.   --
  183.   procedure set_defaults(sensitivity in number);
  184.   --  Set various defaults for this package.
  185.   --  Input parameters:
  186.   --    sensitivity
  187.   --      In case a polling loop is required (see "Implementation Details"
  188.   --      above), this is the time to sleep between polls.  Deafult is 5 sec.
  189.   --
  190.   procedure register(name in varchar2);
  191.   --  Register interest in an alert.  A session may register interest in
  192.   --    an unlimited number of alerts.  Alerts should be de-registered when
  193.   --    the session no longer has any interest (see 'remove').  This call
  194.   --    always performs a 'commit'.
  195.   --  Input parameters:
  196.   --    name
  197.   --      The name of the alert in which this session is interested.
  198.   --      WARNING:  Alert names beginning with 'ORA$' are reserved for use for
  199.   --      products provided by Oracle Corporation.  Name must be 30 bytes
  200.   --      or less.  The name is case-insensitive.
  201.   --
  202.   procedure remove(name in varchar2);
  203.   --  Remove alert from registration list.  Do this when the session is no
  204.   --    longer interested in an alert.  Removing an alert is important
  205.   --    since it will reduce the amount of work done by signalers of the alert.
  206.   --    If a session dies without removing the alert, that alert will
  207.   --    eventually (but not immediately) be cleaned up.  This call always
  208.   --    performs a commit.
  209.   --  Input parameters:
  210.   --    name
  211.   --      The name of the alert to be removed from registration list. The
  212.   --      name is case-insensitive.
  213.   --
  214.   procedure removeall;
  215.   --  Remove all alerts for this session from registration list.  Do this 
  216.   --    when the session is no longer interested in any alerts.  Removing 
  217.   --    alerts is important since it will reduce the amount of work done 
  218.   --    by signalers of the alert.  If a session dies without removing all
  219.   --    of its alerts, the alerts will eventually (but not immediately)
  220.   --    be cleaned up.  This call always performs a commit.
  221.   --
  222.   --    This procedure is called automatically upon first reference to this
  223.   --    package during a session.  Therefore no alerts from prior sessions
  224.   --    which may have terminated abnormally can affect this session.
  225.   procedure waitany(name out varchar2, 
  226.                     message out varchar2, 
  227.                     status out integer,
  228.                     timeout in number default maxwait);
  229.   --  Wait for an alert to occur for any of the alerts for which this
  230.   --    session is registered.  Although probably unusual, the same session
  231.   --    that waits for the alert may also first signal the alert.  In this
  232.   --    case remember to commit after the signal and prior to the wait.  
  233.   --    Otherwise a lock request exception (status 4) will occur.  This
  234.   --    call always performs a commit.
  235.   --  Input parameters:
  236.   --    timeout
  237.   --      The maximum time to wait for an alert.  If no alert occurs before
  238.   --      timeout seconds, then this call will return with status of 1.
  239.   --  Output parameters:
  240.   --    name
  241.   --      The name of the alert that occurred, in uppercase.
  242.   --    message
  243.   --      The message associated with the alert.  This is the message
  244.   --      provided by the 'signal' call.  Note that if multiple signals
  245.   --      on this alert occurred before the waitany call, then the message
  246.   --      will correspond to the most recent signal call.  Messages from
  247.   --      prior signal calls will be discarded.
  248.   --    status
  249.   --      0 - alert occurred
  250.   --      1 - timeout occurred
  251.   --  Errors raised:
  252.   --    -20000, ORU-10024: there are no alerts registered.
  253.   --       Cause: You must register an alert before waiting.
  254.   --
  255.   procedure waitone(name in varchar2, 
  256.                     message out varchar2, 
  257.                     status out integer,
  258.                     timeout in number default maxwait);
  259.   --  Wait for specified alert to occur. If the alert was signalled since
  260.   --    the register or last waitone/waitany, then this call will return
  261.   --    immediately.  The same session that waits for the alert may also
  262.   --    first signal the alert.  In this case remember to commit after the
  263.   --    signal and prior to the wait.  Otherwise a lock request exception
  264.   --    (status 4) will occur.  This call always performs a commit.
  265.   --  Input parameters:
  266.   --    name
  267.   --      The name of the alert to wait for. The name is case-insensitive.
  268.   --    timeout
  269.   --      The maximum time to wait for this alert.  If no alert occurs before
  270.   --      timeout seconds, then this call will return with status of 1.
  271.   --      If the named alert has not been registered then the this call
  272.   --      will return after the timeout period expires.
  273.   --  Output parameters:
  274.   --    message
  275.   --      The message associated with the alert.  This is the message
  276.   --      provided by the 'signal' call.  Note that if multiple signals
  277.   --      on this alert occurred before the waitone call, then the message
  278.   --      will correspond to the most recent signal call.  Messages from
  279.   --      prior signal calls will be discarded.  The message may be up to
  280.   --      1800 bytes.
  281.   --    status
  282.   --      0 - alert occurred
  283.   --      1 - timeout occurred
  284.   --
  285.   procedure signal(name in varchar2, 
  286.                    message in varchar2);
  287.   --  Signal an alert.
  288.   --  Input parameters:
  289.   --    name
  290.   --      Name of the alert to signal.  The effect of the signal call only
  291.   --      occurs when the transaction in which it is made commits.  If the
  292.   --      transaction rolls back, then the effect of the signal call is as
  293.   --      if it had never occurred.  All sessions that have registered
  294.   --      interest in this alert will be notified.  If the interested sessions
  295.   --      are currently waiting, they will be awakened.  If the interested
  296.   --      sessions are not currently waiting, then they will be notified the
  297.   --      next time they do a wait call.  Multiple sessions may concurrently
  298.   --      perform signals on the same alert.  However the first session
  299.   --      will block concurrent sessions until the first session commits.
  300.   --      Name must be 30 bytes or less. It is case-insensitive.  This call
  301.   --      does not perform a commit.
  302.   --    message
  303.   --      Message to associate with this alert.  This will be passed to
  304.   --      the waiting session.  The waiting session may be able to avoid
  305.   --      reading the database after the alert occurs by using the
  306.   --      information in this message.  The message must be 1800 bytes or less.
  307.  
  308. end;
  309. /
  310.  
  311.