UTL_REF: Referencing Objects (Oracle8.0.4)

The UTL_REF package provides a PL/SQL interface that allows you to select and modify objects (instances of an object type) in an object table without having to specify or know about the underlying database table. With UTL_REF, you only need a reference to the object in order to identify it in the database and perform the desired operations. With UTL_REF, you can do any of the following:

  • Select or retrieve an object from the database

  • Lock an object so that no other session can make changes to the object

  • Select and lock an object in a single operation (similar to SELECT FOR UPDATE)

  • Update the contents of an object

  • Delete an object

You will typically use UTL_REF programs when you have references to an object and one of the following is true:

  • You do not want to have to resort to an SQL statement to perform the needed action.

  • You do not even know the name of the table that contains the object, and therefore cannot rely on SQL to get your job done.

Before getting into the details, let’s start with an initial example of how you might use the UTL_REF packages.

You will be able to use UTL_REF programs only to select or modify objects in an object table. An object table is a table in which each row of the table is an object. Here are the steps one might take to create an object table.

First, create an object type:

CREATE TYPE hazardous_site_t IS OBJECT (
   name VARCHAR2(100),
   location VARCHAR2(100),
   dixoin_level NUMBER,
   pcb_level NUMBER,
   METHOD FUNCTION cleanup_time RETURN NUMBER);

Now you can create a table of these objects:

CREATE TABLE hazardous_sites OF hazardous_site_t;

As you will see in the headers for the UTL_REF programs, Oracle has provided a special parameter-passing syntax called ANY. This syntax allows us to pass references and objects of any object type in and out of the programs. This behavior is not otherwise available in Oracle8 built-in packages or the code that you yourself can write using object types.

Getting Started with UTL_REF

The UTL_REF package is created when the Oracle8.0.4 (or later) database is installed. The utlref.sql script (found in the built-in packages source code directory, as described in Chapter 1) contains the source code for this package’s specification. The script is called by catproc.sql, which is normally run immediately after the database is created. The script creates the public synonym UTL_REF for the package and grants EXECUTE privilege on the package to public. All Oracle users can reference and make use of the package.

Every program in this package runs as “owner.” This means that programs in the UTL_REF package operate within the privileges of the session running those programs. You will be able to select and modify only objects to which your session has been granted the necessary privileges.

UTL_REF programs

Table 9.5 lists the programs defined for the UTL_REF packages.

Table 9-5. UTL_REF Programs

Name

Description

Use in SQL

DELETE_OBJECT

Deletes an object from the underlying object table

No

LOCK_OBJECT

Locks an object so that another session cannot change the object

No

SELECT_OBJECT

Selects an object based on its reference, returning that object as an OUT argument

No

UPDATE_OBJECT

Updates the object specified by the reference by replacing it with the object you pass to the program

No

UTL_REF does not declare any nonprogram elements.

UTL_REF exceptions

UTL_REF does not declare any exceptions. However, you may encounter any of the following Oracle exceptions when running the UTL_REF programs:

ORA-00942

Insufficient privileges. You must have the appropriate privileges on the underlying database table.

ORA-01031

Insufficient privileges. You attempted to update an object table on which you have only SELECT privileges. You must have the appropriate privileges on the underlying database table.

ORA-08177

Cannot serialize access for this transaction. You have tried to change data after the start of a serialized transaction.

ORA-00060

Deadlock detected while waiting for resource. Your session and another session are waiting for a resource locked by the other. You will need to wait or ROLLBACK.

ORA-01403

No data found. The REF is NULL or otherwise not associated with an object in the database.

UTL_REF Interface

This section describes the programs available through the UTL_REF package. A single, extended example at the end of the chapter shows how you might be able to take advantage of the UTL_REF programs in your own applications.

The UTL_REF.DELETE_OBJECT procedure

Use the DELETE_OBJECT procedure to delete an object (actually, the row containing that object) specified by the given reference. The header is,

PROCEDURE UTL_REF.DELETE_(reference IN REF ANY);

where reference identifies the object.

This program effectively substitutes for the following kind of SQL statement:

DELETE FROM the_underlying_object_table t
 WHERE REF (t) = reference;

In contrast to this SQL statement, with DELETE_OBJECT you will not need to specify the name of the underlying database object table to retrieve the object.

Restrictions

Note the following restrictions on calling DELETE_OBJECT:

  • The program does not assert a purity level with the RESTRICT_REFERENCES pragma.

  • You cannot call this program from within an SQL statement, either directly or indirectly.

The UTL_REF.LOCK_OBJECT procedure

Use the LOCK_OBJECT procedure to lock or lock and retrieve an object for a given reference. The header is overloaded as follows:

PROCEDURE UTL_REF.LOCK_OBJECT (reference IN REF ANY);

PROCEDURE UTL_REF.LOCK_OBJECT 
   (reference IN REF ANY
   ,object IN OUT ANY);

Parameters are summarized in the following table.

Parameter

Description

reference

The reference to the object

object

The value of the object selected from the database (if supplied)

If you call LOCK_OBJECT and do not provide a second argument, then the object will be locked, but that object will not be returned to the calling program.

This program effectively substitutes for the following type of SQL statement:

SELECT VALUE (t)
  INTO object
  FROM the_underlying_object_table t
 WHERE REF (t) = reference
   FOR UPDATE;

In contrast to this SQL statement, with LOCK_OBJECT you will not need to specify the name of the underlying database object table to retrieve the object.

Note

It is not necessary to lock an object before you update or delete it. By requesting a lock, however, you ensure that another session cannot even attempt to make changes to that same object until you commit or roll back.

Restrictions

Note the following restrictions on calling LOCK_OBJECT:

  • The program does not assert a purity level with the RESTRICT_REFERENCES pragma.

  • You cannot call this program from within an SQL statement, either directly or indirectly.

The UTL_REF.SELECT_OBJECT procedure

Use the SELECT_OBJECT procedure to retrieve an object for a given reference. The header follows:

PROCEDURE UTL_REF.SELECT_OBJECT 
   (reference IN REF ANY
   ,object IN OUT ANY);

Parameters are summarized in the following table.

Parameter

Description

reference

The reference to the object

object

The value of the object selected from the database

This program effectively substitutes for the following type of SQL statement:

SELECT VALUE (t)
  INTO object
  FROM the_underlying_object_table t
 WHERE REF (t) = reference;

In contrast to this SQL statement, with SELECT_OBJECT you will not need to specify the name of the underlying database object table to retrieve the object.

Restrictions

Note the following restrictions on calling SELECT_OBJECT:

  • The program does not assert a purity level with the RESTRICT_REFERENCES pragma.

  • You cannot call this program from within an SQL statement, either directly or indirectly.

Example

In the following procedure, I use the SELECT_OBJECT built-in to retrieve the object based on the passed-in reference:

CREATE OR REPLACE PROCEDURE show_emp (emp_in IN REF employee_t)
IS
   emp_obj employee_t
BEGIN
   UTL_REF.SELECT_OBJECT (emp_in, emp_obj);
   DBMS_OUTPUT.PUT_LINE (emp_obj.name);
END;.

The UTL_REF.UPDATE_OBJECT procedure

Use the UPDATE_OBJECT procedure to replace an object in the database specified by a given reference with your “replacement” object. Here’s the header:

PROCEDURE UTL_REF.UPDATE_OBJECT 
   (reference IN REF ANY
   ,object IN ANY);

Parameters are summarized in the following table.

Parameter

Description

reference

The reference to the object

object

The object that is to be placed in the row of the object table specified by the reference

This program effectively substitutes for the following type of SQL statement:

UPDATE the_underlying_object_table t 
   SET VALUE (t) = object
 WHERE REF (t) = reference;

In contrast to this SQL statement, with UPDATE_OBJECT you will not need to specify the name of the underlying database object table to retrieve the object.

Restrictions

Note the following restrictions on calling UPDATE_OBJECT:

  • The program does not assert a purity level with the RESTRICT_REFERENCES pragma.

  • You cannot call this program from within an SQL statement, either directly or indirectly.

UTL_REF Example

Let’s start with an object type that can hold various types of documents

CREATE OR REPLACE TYPE Document_t AS OBJECT (
   doc_id NUMBER,
   author VARCHAR2(65),
   created DATE,
   revised DATE,
   body BLOB,
   MEMBER PROCEDURE update_revised
);
/

To keep this example simple, we’ll implement only a single object method:

CREATE OR REPLACE TYPE BODY Document_t
AS
   MEMBER PROCEDURE update_revised
   IS
   BEGIN
      revised := SYSDATE;
   END;
END;
/

Here’s a table that will hold any kind of document:

CREATE TABLE documents OF Document_t;

We might have a requisition type that has a special type of document. Each requisition contains a REF to a particular document.

CREATE OR REPLACE TYPE Requisition_t AS OBJECT (
   doc_ref REF Document_t,
   needed DATE,
   approved DATE,
   MEMBER PROCEDURE update_revision_date,
   MEMBER FUNCTION has_valid_need_date RETURN BOOLEAN
);
/

In a moment, we’re going to look at an example of UTL_REF that implements the type body of Requisition_t. But let’s first look at life without UTL_REF. Not only do we have to write SQL, we also have to know the table name in each statement where we need access to a persistent object. In fact, the following methods are hard-coded to work with only one particular table implementation (not good):

CREATE OR REPLACE TYPE BODY Requisition_t
AS
   MEMBER FUNCTION has_valid_need_date RETURN BOOLEAN
   IS
      document Document_t;
      CURSOR doc_cur IS                /* Ugly! */
         SELECT VALUE(d) 
           FROM documents d
          WHERE REF(d) = SELF.doc_ref;
   BEGIN
      OPEN doc_cur;
      FETCH doc_cur INTO document;    /* Ditto */
      CLOSE doc_cur;
      IF document.created > SELF.approved
      THEN
         RETURN FALSE;
      ELSE
         RETURN TRUE;
      END IF;
   END;
   MEMBER PROCEDURE update_revision_date
   IS
   BEGIN
      UPDATE documents d            /* Even uglier */
         SET revised = SYSDATE
       WHERE REF(d) = SELF.doc_ref;
   END;
END;
/

Let’s turn now to see what UTL_REF can do for us:

CREATE OR REPLACE TYPE BODY Requisition_t
AS
   MEMBER FUNCTION has_valid_need_date RETURN BOOLEAN
   IS
      document Document_t;
   BEGIN
      /* UTL_REF.SELECT_OBJECT allows us to retrieve the document object 
      || from persistent database storage into a local variable.  No muss, 
      || no fetch, no bother!  SELECT_OBJECT finds the table and object 
      || for us.
      */
      UTL_REF.SELECT_OBJECT (SELF.doc_ref, document);
      /* Now that we have retrieved the document object, we can
      || easily gain access to its attributes:
      */
      IF document.created > SELF.approved
      THEN
         RETURN FALSE;
      ELSE
         RETURN TRUE;
      END IF;
   END;
   MEMBER PROCEDURE update_revision_date
   IS
      document Document_t;
   BEGIN
      /* To update the revision date of the requisition object,
      || we'll simply "delegate" to the referenced document.
      || First we retrieve it...
      */
      UTL_REF.SELECT_OBJECT (SELF.doc_ref, document);
      /* ...then we can invoke a method on the newly retrieved
      || (but transient) object.  Notice that we do NOT update
      || the attribute directly, but rely instead on the public
      || method supplied for this purpose.
      */
      document.update_revised;
      /* ...and now we easily update the data in the underlying table
      || (whatever table it is...we don't know or care!)
      */
      UTL_REF.UPDATE_OBJECT(SELF.doc_ref, document);
   END;
END;
/

Since UTL_REF frees us from dependence on the specific underlying table, it allows us to achieve greater reuse, portability, modularity, and resilience to change.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset