rem 
rem $Header: dbmslock.sql,v 1.11 1994/03/29 16:23:17 adowning Exp $ 
rem 
Rem  Copyright (c) 1991 by Oracle Corporation 
Rem    NAME
Rem      dbmslock.sql - locking routines provided by Oracle
Rem    DESCRIPTION
Rem      See below
Rem    RETURNS
Rem
Rem    NOTES
Rem     The procedural option is needed to use this facility.
Rem
Rem     Lockids from 2000000000 to 2147483647 are reserved for products
Rem     supplied by Oracle:
Rem
Rem       Package                     Lock id range
Rem       =================================================
Rem       dbms_alert                  2000000000-2000002041
Rem       dbms_alert                  2000002042-2000003063
Rem
Rem    MODIFIED   (MM/DD/YY)
Rem     adowning   03/29/94 -  merge changes from branch 1.10.710.1
Rem     adowning   02/02/94 -  split file into public / private binary files
Rem     rkooi      12/03/92 -  change comments 
Rem     rkooi      11/25/92 -  return 5 instead of 6 per spec 
Rem     rkooi      11/24/92 -  check for nulls 
Rem     rkooi      11/18/92 -  add comments 
Rem     rkooi      08/20/92 -  comments and cleanup 
Rem     rkooi      06/29/92 -  add some comments 
Rem     rkooi      05/30/92 -  fix timeout problems 
Rem     rkooi      04/30/92 -  add some comments 
Rem     rkooi      04/25/92 -  misc change 
Rem     rkooi      04/12/92 -  Creation 

Rem This script must be run as user SYS

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

create or replace package dbms_lock is

  ------------
  --  OVERVIEW
  --
  --  These routines allow the user to request, convert and release locks.
  --  The locks are managed by the rdbms lock management services.  All
  --  lock ids are prepended with the 'UL' prefix so that they cannot
  --  conflict with DBMS locks.  These locks will show up in the SQL*DBA
  --  lock monitor screen and in the appropriate fixed views.
  --
  --  Deadlock detection is performed on these locks.
  --
  --  Locks are automatically released when the session terminates.
  --  It is up to the clients to agree on the use of these locks.  The
  --  lock identifier is a number in the range of 0 to 1073741823.  
  --
  --  The allocate_unique call can be used to allocate a unique lockid
  --  (in the range of 1073741824 to 1999999999) given a lock name.  This is
  --  provided since it may be easier for applications to coordinate
  --  their use of locks based on lock names rather than lock numbers.
  --  The first session to call allocate_unique with a new lock name will
  --  cause a unique lockid to be generated and stored in the
  --  dbms_lock_allocated table.  Subsequent calls (usually by other
  --  sessions) will return the lockid previously generated.  A lock name
  --  will be associated with the returned lockid for at least
  --  'expiration_secs' (defaults to 10 days) past the last call to
  --  allocate_unique with the given lock name.  After this time, the row
  --  in the dbms_lock_allocated table for this lock name may be deleted
  --  in order to recover space.  Allocate_unique performs a commit.
  --
  --  A sleep procedure is also provided which causes the caller to sleep
  --  for the given interval.


  ------------------------------------------------
  --  SUMMARY OF SERVICES PROVIDED BY THIS PACKAGE
  --
  --  allocate_unique - allocate a unique lock given a name
  --  request	      - request a lock of given mode
  --  convert	      - convert lock from one mode to another
  --  releas          - release the lock
  --  sleep	      - sleep for the specified time


  ---------------
  --  LIMITATIONS
  --
  --  The implementation does not support large numbers of locks efficiently.
  --  A few hundred locks per session should be the limit.


  ------------
  --  SECURITY
  --
  --  There may be OS-specific limits on the maximum number of total
  --  locks available.  You will need to consider this when using locks,
  --  or making this package available to users.  You may wish to only
  --  grant execute to those users or roles that you trust.  An
  --  alternative is to create a cover package for this package which
  --  limits those locks used.  Then, instead of granting execute on this
  --  package to public, grant execute on the cover package
  --  only to specific users.  A cover package might look like this:
  --
  --  create package lock_100_to_200 is
  --    nl_mode  constant integer := 1;
  --    ss_mode  constant integer := 2;
  --    sx_mode  constant integer := 3;
  --    s_mode   constant integer := 4;
  --    ssx_mode constant integer := 5;
  --    x_mode   constant integer := 6;
  --    maxwait  constant integer := 32767;
  --    function request(id in integer,
  --                     lockmode in integer default x_mode, 
  --                     timeout in integer default maxwait,
  --                     release_on_commit in boolean default FALSE)
  --      return integer;
  --    function convert(id in integer;
  --                     lockmode in integer, 
  --                     timeout in number default maxwait)
  --      return integer;
  --    function release(id in integer) return integer;
  --  end;
  --  create package body lock_100_to_200 is
  --  begin
  --    function  request(id in integer,
  --                     lockmode in integer default x_mode, 
  --                     timeout in integer default maxwait,
  --                     release_on_commit in boolean default FALSE)
  --      return integer is
  --    begin
  --      if id < 100 or id > 200 then
  --        raise_application_error(-20000,'Lock id out of range');
  --      endif;
  --      return dbms_lock.request(id, lockmode, timeout, release_on_commit);
  --    end;
  --    function convert(id in integer,
  --                     lockmode in integer, 
  --                     timeout in number default maxwait)
  --      return integer is
  --    begin
  --      if id < 100 or id > 200 then
  --        raise_application_error(-20000,'Lock id out of range');
  --      endif;
  --      return dbms_lock.convert(id, lockmode, timeout);
  --    end;
  --    function release(id in integer) return integer is
  --    begin
  --      if id < 100 or id > 200 then
  --        raise_application_error(-20000,'Lock id out of range');
  --      endif;
  --      return dbms_lock.release(id);
  --    end;
  --  end;
  --  
  --  Grant execute on the lock_100_to_200 package to those users who
  --  are allowed to use locks in the 100-200 range.  Don't grant execute
  --  on package dbms_lock to anyone.  The lock_100_200 package
  --  should be created as sys.
  --
  --  The "dbms_session.is_role_enabled" procedure could also be used
  --  in a cover package to enforce security.

  ---------------------
  --  SPECIAL CONSTANTS
  --
  nl_mode  constant integer := 1;
  ss_mode  constant integer := 2;	-- Also called 'Intended Share'
  sx_mode  constant integer := 3;	-- Also called 'Intended Exclusive'
  s_mode   constant integer := 4;
  ssx_mode constant integer := 5;
  x_mode   constant integer := 6;
  --  These are the various lock modes (nl -> "NuLl", ss -> "Sub Shared",
  --  sx -> "Sub eXclusive", s -> "Shared", ssx -> "Shared Sub eXclusive",
  --  x -> "eXclusive").
  --
  --  A sub-share lock can be used on an aggregate object to indicate that 
  --  share locks are being aquired on sub-parts of the object.  Similarly, a
  --  sub-exclusive lock can be used on an aggregate object to indicate
  --  that exclusive locks are being aquired on sub-parts of the object.  A
  --  share-sub-exclusive lock indicates that the entire aggregate object
  --  has a share lock, but some of the sub-parts may additionally have
  --  exclusive locks.
  --
  --  Lock Compatibility Rules:
  --  When another process holds "held", an attempt to get "get" does
  --  the following:
  --
  --  held  get->  NL   SS   SX   S    SSX  X
  --  NL           SUCC SUCC SUCC SUCC SUCC SUCC
  --  SS           SUCC SUCC SUCC SUCC SUCC fail
  --  SX           SUCC SUCC SUCC fail fail fail
  --  S            SUCC SUCC fail SUCC fail fail
  --  SSX          SUCC SUCC fail fail fail fail
  --  X            SUCC fail fail fail fail fail
  --
  maxwait  constant integer := 32767;
  -- maxwait means to wait forever


  ----------------------------
  --  PROCEDURES AND FUNCTIONS
  --
  procedure allocate_unique(lockname in varchar2, 
			    lockhandle out varchar2,
			    expiration_secs in integer default 864000);
  --  Given a name, generate a unique lockid for this lock.  This procedure
  --    always performs a 'commit'.
  --  Input parameters:
  --    lockname    
  --      name of lock to generate unique lockid for.  If this name already
  --      has been assigned a lockid, then return a handle to that lockid.
  --      Otherwise generate a new lockid and return a handle to it.
  --      WARNING: Do not use locknames beginning with 'ORA$'; these names
  --      are reserved for products supplied by Oracle Corporation.  The
  --      name can be up to 128 bytes, and is case-sensitive.
  --    expiration_secs
  --      number of seconds after an 'allocate_unique' is last performed on
  --      this lock name that this lock is subject to cleanup (i.e.,
  --      deleting from the dbms_lock_allocated table).  Defaults to 10
  --      days.
  --  Output parameters:
  --    lockhandle
  --      The actual lockid is not returned, rather a handle to it is
  --      returned.  Use this handle in subsequent calls to request,
  --      convert and release. Up to 128 bytes are returned.  A handle
  --      is used to reduce the chance that a programming error can
  --      accidentally create an incorrect but valid lockid.  This will
  --      provide better isolation between different applications that are
  --      using this package.
  --
  --      All sessions using a lockhandle returned by a call to
  --      allocate_unique using the same name will be referring to the same
  --      lock.  Different sessions may have different lockhandles for the
  --      same lock, so lockhandles should not be passed from one session
  --      to another.
  --
  --      The lockid's generated by allocate_unique are between 1073741824
  --      and 1999999999, inclusive.
  --
  --      This routine will always do a commit.
  --
  --  Errors raised:
  --    -20000, ORU-10003: Unable to find or insert lock <lockname>
  --        into catalog dbms_lock_allocated.
  
  function  request(id in integer,
                    lockmode in integer default x_mode, 
                    timeout in integer default maxwait,
                    release_on_commit in boolean default FALSE)
    return integer;
  function  request(lockhandle in varchar2,
                    lockmode in integer default x_mode, 
                    timeout in integer default maxwait,
                    release_on_commit in boolean default FALSE)
    return integer;
  --  Request a lock with the given mode. Note that this routine is
  --    overloaded based on the type of its first argument.  The
  --    appropriate routine is used based on how it is called.
  --    If a deadlock is detected, then an arbitrary session is
  --    chosen to receive deadlock status.
  --    ***NOTE*** When running both multi-threaded server (dispatcher) AND
  --    parallel server, a multi-threaded "shared server" will be
  --    bound to a session during the time that any locks are held.
  --    Therefore the "shared server" will not be shareable during this time.
  --  Input parameters:
  --    id
  --      From 0 to 1073741823.  All sessions that use the same number will
  --      be referring to the same lock. Lockids from 2000000000 to
  --      2147483647 are accepted by this routine.  Do not use these as 
  --      they are reserved for products supplied by Oracle Corporation.
  --    lockhandle
  --      Handle returned by call to allocate_unique.
  --    lockmode
  --      See lockmodes and lock compatibility table above
  --    timeout
  --      Timeout in seconds.  If the lock cannot be granted within this
  --      time period then the call returns a value of 1.  Deadlock
  --      detection is performed for all "non-small" values of timeout.
  --    release_on_commit 
  --      If TRUE, then release on commit or rollback, otherwise keep until
  --      explicitly released or until end-of-session.  If a transaction
  --      has not been started, it will be.
  --  Return value:
  --    0 - success
  --    1 - timeout
  --    2 - deadlock
  --    3 - parameter error
  --    4 - already own lock specified by 'id' or 'lockhandle'
  --    5 - illegal lockhandle
  --
  function convert(id in integer, 
                   lockmode in integer, 
                   timeout in number default maxwait)
    return integer;
  function convert(lockhandle in varchar2, 
                   lockmode in integer, 
                   timeout in number default maxwait)
    return integer;
  --  Convert a lock from one mode to another. Note that this routine is
  --    overloaded based on the type of its first argument.  The
  --    appropriate routine is used based on how it is called.
  --    If a deadlock is detected, then an arbitrary session is
  --    chosen to receive deadlock status.
  --  Input parameters:
  --    id
  --      From 0 to 1073741823.
  --    lockhandle
  --      Handle returned by call to allocate_unique.
  --    lockmode
  --      See lockmodes and lock compatibility table above.
  --    timeout
  --      Timeout in seconds.  If the lock cannot be converted within this
  --      time period then the call returns a value of 1.  Deadlock
  --      detection is performed for all "non-small" values of timeout.
  --  Return value:
  --    0 - success
  --    1 - timeout
  --    2 - deadlock
  --    3 - parameter error
  --    4 - don't own lock specified by 'id' or 'lockhandle'
  --    5 - illegal lockhandle
  --
  function release(id in integer) return integer;
  function release(lockhandle in varchar2) return integer;
  --  Release a lock previously aquired by 'request'. Note that this routine
  --    is overloaded based on the type of its argument.  The
  --    appropriate routine is used based on how it is called.
  --  Input parameters:
  --    id
  --      From 0 to 1073741823.
  --  Return value:
  --    0 - success
  --    3 - parameter error
  --    4 - don't own lock specified by 'id' or 'lockhandle'
  --    5 - illegal lockhandle
  --
  procedure sleep(seconds in number);
  --  Suspend the session for the specified period of time.
  --  Input parameters:
  --    seconds
  --      In seconds, currently the maximum resolution is in hundreths of 
  --      a second (e.g., 1.00, 1.01, .99 are all legal and distinct values).

end;
/

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