Oracle8 Server Application Developer's Guide
Release 8.0
A54642_01

Library

Product

Contents

Index


Prev Next

10
Using Procedures and Packages

This chapter discusses the procedural capabilities of Oracle, including:

Note: If you are using Trusted Oracle, also see the Trusted Oracle Server Administrator's Guide for additional information.

PL/SQL Procedures and Packages

PL/SQL is a modern, block-structured programming language. It provides you with a number of features that make developing powerful database applications very convenient. For example, PL/SQL provides procedural constructs, such as loops and conditional statements, that you do not find in standard SQL.

You can directly issue SQL data manipulation language (DML) statements inside PL/SQL blocks, and you can use procedures, supplied by Oracle, to perform data definition language (DDL) statements.

PL/SQL code executes on the server, so using PL/SQL allows you to centralize significant parts of your database applications for increased maintainability and security. It also enables you to achieve a significant reduction of network overhead in client/server applications.

Note: Some Oracle tools, such as Oracle Forms, contain a PL/SQL engine, and can execute PL/SQL locally.

You can even use PL/SQL for some database applications in place of 3GL programs that use embedded SQL or the Oracle Call Interface (OCI).

There are several kinds of PL/SQL program units:

For complete information about the PL/SQL language, see the PL/SQL User's Guide and Reference.

Anonymous Blocks

An anonymous PL/SQL block consists of an optional declarative part, an executable part, and one or more optional exception handlers.

You use the declarative part to declare PL/SQL variables, exceptions, and cursors. The executable part contains PL/SQL code and SQL statements, and can contain nested blocks. Exception handlers contain code that is called when the exception is raised, either as a predefined PL/SQL exception (such as NO_DATA_FOUND or ZERO_DIVIDE), or as an exception that you define.

The following short example of a PL/SQL anonymous block prints the names of all employees in department 20 in the EMP table, using the DBMS_OUTPUT package (described on page 12-19):

DECLARE

    emp_name    VARCHAR2(10);

    CURSOR      c1 IS SELECT ename FROM emp

                        WHERE deptno = 20;

BEGIN

    LOOP

        FETCH c1 INTO emp_name;

        EXIT WHEN c1%NOTFOUND;

        DBMS_OUTPUT.PUT_LINE(emp_name);

    END LOOP;

END;

Note: If you try this block out using SQL*Plus make sure to issue the command SET SERVEROUTPUT ON so that output using the DBMS_OUTPUT procedures such as PUT_LINE is activated. Also, terminate the example with a slash (/) to activate it.

Exceptions allow you to handle Oracle error conditions within PL/SQL program logic. This allows your application to prevent the server from issuing an error that could cause the client application to abort. The following anonymous block handles the predefined Oracle exception NO_DATA_FOUND (which would result in an ORA-01403 error if not handled):

DECLARE

    emp_number   INTEGER := 9999;

    emp_name     VARCHAR2(10);

BEGIN

    SELECT ename INTO emp_name FROM emp

        WHERE empno = emp_number;   -- no such number

    DBMS_OUTPUT.PUT_LINE('Employee name is ' || emp_name);

EXCEPTION

    WHEN NO_DATA_FOUND THEN

        DBMS_OUTPUT.PUT_LINE('No such employee: ' || emp_number);

END;

You can also define your own exceptions, declare them in the declaration part of a block, and define them in the exception part of the block. An example follows:

DECLARE

    emp_name           VARCHAR2(10);

    emp_number         INTEGER;

    empno_out_of_range EXCEPTION;

BEGIN

    emp_number := 10001;

    IF emp_number > 9999 OR emp_number < 1000 THEN

        RAISE empno_out_of_range;

    ELSE

        SELECT ename INTO emp_name FROM emp

            WHERE empno = emp_number;

        DBMS_OUTPUT.PUT_LINE('Employee name is ' || emp_name);

END IF;

EXCEPTION

    WHEN empno_out_of_range THEN

        DBMS_OUTPUT.PUT_LINE('Employee number ' || emp_number ||

          ' is out of range.');

END;

See the PL/SQL User's Guide and Reference for a complete treatment of exceptions.

Anonymous blocks are most often used either interactively, from a tool such as SQL*Plus, or in a precompiler, OCI, or SQL*Module application. They are normally used to call stored procedures, or to open cursor variables. (See page 10-24 for a description of cursor variables.)

Database Triggers

A database trigger is a special kind of PL/SQL anonymous block. You can define triggers to fire before or after SQL statements, either on a statement level or for each row that is affected. See Chapter 13, "Using Database Triggers" in this Guide for more information.

Stored Procedures and Functions

A stored procedure or function is a PL/SQL program unit that

Note: The term stored procedure is sometimes used generically in this Guide to cover both stored procedures and stored functions.

Procedure Names

Since a procedure is stored in the database, it must be named, to distinguish it from other stored procedures, and to make it possible for applications to call it. Each publicly-visible procedure in a schema must have a unique name. The name must be a legal PL/SQL identifier.

Note: If you plan to call a stored procedure using a stub generated by SQL*Module, the stored procedure name must also be a legal identifier in the calling host 3GL language such as Ada or C.

Procedure and function names that are part of packages can be overloaded. That is, you can use the same name for different subprograms as long as their formal parameters differ in number, order, or datatype family. See PL/SQL User's Guide and Reference for more information about subprogram name overloading.

Procedure Parameters

Stored procedures and functions can take parameters. The following example shows a stored procedure that is similar to the anonymous block on page 10-3:

PROCEDURE get_emp_names (dept_num IN NUMBER) IS

    emp_name       VARCHAR2(10);

    CURSOR         c1 (depno NUMBER) IS

                      SELECT ename FROM emp

                        WHERE deptno = depno;



BEGIN

    OPEN c1(dept_num);

    LOOP

        FETCH c1 INTO emp_name;

        EXIT WHEN c1%NOTFOUND;

        DBMS_OUTPUT.PUT_LINE(emp_name);

    END LOOP;

    CLOSE c1;

END;

In the stored procedure example, the department number is an input parameter, which is used when the parameterized cursor C1 is opened.

The formal parameters of a procedure have three major parts:

name  

The name of the parameter, which must be a legal PL/SQL identifier.  

mode  

The parameter mode, which indicates whether the parameter is an input-only parameter (IN), an output-only parameter (OUT), or is both an input and an output parameter (IN OUT). If the mode is not specified, IN is assumed.  

datatype  

The parameter datatype is a standard PL/SQL datatype.  

Parameter Modes

You use parameter modes to define the behavior of formal parameters. The three parameter modes, IN (the default), OUT, and IN OUT, can be used with any subprogram. However, avoid using the OUT and IN OUT modes with functions. The purpose of a function is to take zero or more arguments and return a single value. It is poor programming practice to have a function return multiple values. Also, functions should be free from side effects, which change the values of variables not local to the subprogram.

Table 10-1 summarizes the information about parameter modes. Parameter modes are explained in detail in the PL/SQL User's Guide and Reference.

Table 10-1: Parameter Modes

IN  

OUT  

IN OUT  

the default  

must be specified  

must be specified  

passes values to a subprogram  

returns values to the caller  

passes initial values to a subprogram; returns updated values to the caller  

formal parameter acts like a constant  

formal parameter acts like an uninitialized variable  

formal parameter acts like an initialized variable  

formal parameter cannot be assigned a value  

formal parameter cannot be used in an expression; must be assigned a value  

formal parameter should be assigned a value  

actual parameter can be a constant, initialized variable, literal, or expression  

actual parameter must be a variable  

actual parameter must be a variable  

Parameter Datatypes

The datatype of a formal parameter consists of one of the following:

Attention: Numerically constrained types such as NUMBER(2) or VARCHAR2(20) are not allowed in a parameter list.

%TYPE and %ROWTYPE Attributes
However, you can use the type attributes %TYPE and %ROWTYPE to constrain the parameter. For example, the GET_EMP_NAMES procedure specification in "Procedure Parameters" on page 10-5 could be written as

PROCEDURE get_emp_names(dept_num IN emp.deptno%TYPE)

to have the DEPT_NUM parameter take the same datatype as the DEPTNO column in the EMP table. The column and table must be available when a declaration using %TYPE (or %ROWTYPE) is elaborated.

Using %TYPE is recommended, since if the type of the column in the table changes, it is not necessary to change the application code.

If the GET_EMP_NAMES procedure is part of a package, then you can use previously-declared public (package) variables to constrain a parameter datatype. For example:

dept_number    number(2);

...

PROCEDURE get_emp_names(dept_num IN dept_number%TYPE);

You use the %ROWTYPE attribute to create a record that contains all the columns of the specified table. The following example defines the GET_EMP_REC procedure, which returns all the columns of the EMP table in a PL/SQL record, for the given EMPNO:

PROCEDURE get_emp_rec (emp_number  IN emp.empno%TYPE,

                       emp_ret    OUT emp%ROWTYPE) IS

BEGIN

    SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno

        INTO emp_ret

        FROM emp

        WHERE empno = emp_number;

END;

You could call this procedure from a PL/SQL block as follows:

DECLARE

  emp_row      emp%ROWTYPE;     -- declare a record matching a

                                -- row in the EMP table

BEGIN

  get_emp_rec(7499, emp_row);   -- call for emp# 7499

  DBMS_OUTPUT.PUT(emp_row.ename || ' ' || emp_row.empno);

  DBMS_OUTPUT.PUT(' ' || emp_row.job || ' ' || emp_row.mgr);

  DBMS_OUTPUT.PUT(' ' || emp_row.hiredate || ' ' || emp_row.sal);

  DBMS_OUTPUT.PUT(' ' || emp_row.comm || ' ' || emp_row.deptno);

  DBMS_OUTPUT.NEW_LINE;

END;

Stored functions can also return values that are declared using %ROWTYPE. For example:

FUNCTION get_emp_rec (dept_num IN emp.deptno%TYPE)

    RETURN emp%ROWTYPE IS ...

Tables and Records

You can pass PL/SQL tables as parameters to stored procedures and functions. You can also pass tables of records as parameters.

Default Parameter Values

Parameters can take default values. You use the DEFAULT keyword or the assignment operator to give a parameter a default value. For example, the specification for the GET_EMP_NAMES procedure on page 10-5 could be written as

PROCEDURE get_emp_names (dept_num IN NUMBER DEFAULT 20) IS ...

or as

PROCEDURE get_emp_names (dept_num IN NUMBER := 20) IS ...

When a parameter takes a default value, it can be omitted from the actual parameter list when you call the procedure. When you do specify the parameter value on the call, it overrides the default value.

DECLARE Keyword

Unlike in an anonymous PL/SQL block, you do not use the keyword DECLARE before the declarations of variables, cursors, and exceptions in a stored procedure. In fact, it is an error to use it.

Creating Stored Procedures and Functions

Use your normal text editor to write the procedure. At the beginning of the procedure, place the command

CREATE PROCEDURE procedure_name AS   ...

For example, to use the example on page 10-7, you can create a text (source) file called get_emp.sql containing the following code:

CREATE PROCEDURE get_emp_rec (emp_number  IN emp.empno%TYPE,

                              emp_ret    OUT emp%ROWTYPE) AS

BEGIN

    SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno

        INTO emp_ret

        FROM emp

        WHERE empno = emp_number;

END;

/

Then, using an interactive tool such as SQL*Plus, load the text file containing the procedure by entering the command

SQLPLUS> @get_emp

to load the procedure into the current schema from the get_emp.sql file (.sql is the default file extension). Note the slash (/) at the end of the code. This is not part of the code; it just activates the loading of the procedure.

Note: When developing a new procedure, it is usually much more convenient to use the CREATE OR REPLACE . . . PROCEDURE command. This replaces any previous version of that procedure in the same schema with the newer version. This is done with no warning.

You can use either the keyword IS or AS after the procedure parameter list.

Use the CREATE [OR REPLACE] FUNCTION . . . command to store functions. See the Oracle8 Server SQL Reference for the complete syntax of the CREATE PROCEDURE and CREATE FUNCTION commands.

Privileges Required to Create Procedures and Functions

To create a stand-alone procedure or function, or package specification or body, you must meet the following prerequisites:

Attention: To create without errors, that is, to compile the procedure or package successfully, requires the following additional privileges:

The owner of the procedure or package must have been explicitly granted the necessary object privileges for all objects referenced within the body of the code; the owner cannot have obtained required privileges through roles.

If the privileges of a procedure's or package's owner change, the procedure must be reauthenticated before it is executed. If a necessary privilege to a referenced object is revoked from the owner of the procedure (or package), the procedure cannot be executed.

The EXECUTE privilege on a procedure gives a user the right to execute a procedure owned by another user. Privileged users execute the procedure under the security domain of the procedure's owner. Therefore, users never have to be granted the privileges to the objects referenced by a procedure. This allows for more disciplined and efficient security strategies with database applications and their users. Furthermore, all procedures and packages are stored in the data dictionary (in the SYSTEM tablespace). No quota controls the amount of space available to a user who creates procedures and packages.

Altering Stored Procedures and Functions

To alter a stored procedure or stored function, you must first DROP it, using the DROP PROCEDURE or DROP FUNCTION command, then recreate it using the CREATE PROCEDURE or CREATE FUNCTION command. Alternatively, use the CREATE OR REPLACE PROCEDURE or CREATE OR REPLACE FUNCTION command, which first drops the procedure or function if it exists, then recreates it as specified.

The procedure or function is dropped with no warning.

External Procedures

A PL/SQL procedure executing on an Oracle Server can call an external procedure, written in a 3GL. The 3GL procedure executes in a separate address space from that of the Oracle Server.

For information about external procedures, see the PL/SQL User's Guide and Reference.

PL/SQL Packages

A package is a group of PL/SQL types, objects, and stored procedures and functions. The specification part of a package declares the public types, variables, constants, and subprograms that are visible outside the immediate scope of the package. The body of a package defines the objects declared in the specification, as well as private objects that are not visible to applications outside the package.

The following example shows a package specification for a package named EMPLOYEE_MANAGEMENT. The package contains one stored function and two stored procedures.

CREATE PACKAGE employee_management AS

   FUNCTION hire_emp (name VARCHAR2, job VARCHAR2,

      mgr NUMBER, hiredate DATE, sal NUMBER, comm NUMBER,

      deptno NUMBER) RETURN NUMBER;

   PROCEDURE fire_emp (emp_id NUMBER);

   PROCEDURE sal_raise (emp_id NUMBER, sal_incr NUMBER);

END employee_management;

The body for this package defines the function and the procedures:

CREATE PACKAGE BODY employee_management AS

   FUNCTION hire_emp (name VARCHAR2, job VARCHAR2,

      mgr NUMBER, hiredate DATE, sal NUMBER, comm NUMBER,

      deptno NUMBER) RETURN NUMBER IS



-- The function accepts all arguments for the fields in

-- the employee table except for the employee number.

-- A value for this field is supplied by a sequence.

-- The function returns the sequence number generated

-- by the call to this function.



       new_empno    NUMBER(10);





   BEGIN

      SELECT emp_sequence.NEXTVAL INTO new_empno FROM dual;

      INSERT INTO emp VALUES (new_empno, name, job, mgr,

         hiredate, sal, comm, deptno);

      RETURN (new_empno);

   END hire_emp;



   PROCEDURE fire_emp(emp_id IN NUMBER) AS



-- The procedure deletes the employee with an employee

-- number that corresponds to the argument EMP_ID.  If

-- no employee is found, an exception is raised.



   BEGIN

      DELETE FROM emp WHERE empno = emp_id;

      IF SQL%NOTFOUND THEN

      raise_application_error(-20011, 'Invalid Employee

         Number: ' || TO_CHAR(emp_id));

   END IF;

END fire_emp;





PROCEDURE sal_raise (emp_id IN NUMBER, sal_incr IN NUMBER) AS



-- The procedure accepts two arguments.  EMP_ID is a

-- number that corresponds to an employee number.

-- SAL_INCR is the amount by which to increase the

-- employee's salary.

   BEGIN



-- If employee exists, update salary with increase.

      UPDATE emp

         SET sal = sal + sal_incr

         WHERE empno = emp_id;

      IF SQL%NOTFOUND THEN

         raise_application_error(-20011, 'Invalid Employee

            Number: ' || TO_CHAR(emp_id));

      END IF;

   END sal_raise;

END employee_management;

Note: If you want to try this example, first create the sequence number EMP_SEQUENCE. You can do this using the following SQL*Plus statement:

SQL> EXECUTE CREATE SEQUENCE emp_sequence

   > START WITH 8000 INCREMENT BY 10;

Creating Packages

Each part of a package is created with a different command. Create the package specification using the CREATE PACKAGE command. The CREATE PACKAGE command declares public package objects.

To create a package body, use the CREATE PACKAGE BODY command. The CREATE PACKAGE BODY command defines the procedural code of the public procedures and functions declared in the package specification. (You can also define private (or local) package procedures, functions, and variables within the package body. See "Local Objects" on page 10-13.

The OR REPLACE Clause

It is often more convenient to add the OR REPLACE clause in the CREATE PACKAGE or CREATE PACKAGE BODY commands when you are first developing your application. The effect of this option is to drop the package or the package body without warning. The CREATE commands would then be

CREATE OR REPLACE PACKAGE package_name AS ...

and

CREATE OR REPLACE PACKAGE BODY package_name AS ...

Privileges Required to Create Packages

The privileges required to create a package specification or package body are the same as those required to create a stand-alone procedure or function; see page 10-9.

Creating Packaged Objects

The body of a package can contain

Procedures, functions, cursors, and variables that are declared in the package specification are global. They can be called, or used, by external users that have execute permission for the package, or that have EXECUTE ANY PROCEDURE privileges.

When you create the package body, make sure that each procedure that you define in the body has the same parameters, by name, datatype, and mode, as the declaration in the package specification. For functions in the package body, the parameters as well as the return type must agree in name and type.

Local Objects

You can define local variables, procedures, and functions in a package body. These objects can only be accessed by other procedures and functions in the body of the same package. They are not visible to external users, regardless of the privileges they hold.

Naming Packages and Package Objects

The names of a package and all public objects in the package must be unique within a given schema. The package specification and its body must have the same name. All package constructs must have unique names within the scope of the package, unless overloading of procedure names is desired.

Dropping Packages and Procedures

A standalone procedure, a standalone function, a package body, or an entire package can be dropped using the SQL commands DROP PROCEDURE, DROP FUNCTION, DROP PACKAGE BODY, and DROP PACKAGE, respectively. A DROP PACKAGE statement drops both a package's specification and body.

The following statement drops the OLD_SAL_RAISE procedure in your schema:

DROP PROCEDURE old_sal_raise;

Privileges Required to Drop Procedures and Packages

To drop a procedure or package, the procedure or package must be in your schema or you must have the DROP ANY PROCEDURE privilege. An individual procedure within a package cannot be dropped; the containing package specification and body must be re-created without the procedures to be dropped.

Package Invalidations and Session State

Each session that references a package object has its own instance of the corresponding package, including persistent state for any public and private variables, cursors, and constants. If any of the session's instantiated packages (specification or body) are subsequently invalidated and recompiled, all other dependent package instantiations (including state) for the session are lost.

For example, assume that session S instantiates packages P1 and P2, and that a procedure in package P1 calls a procedure in package P2. If P1 is invalidated and recompiled (for example, as the result of a DDL operation), the session S instantiations of both P1 and P2 are lost. In such situations, a session receives the following error the first time it attempts to use any object of an invalidated package instantiation:

ORA-04068: existing state of packages has been discarded

The second time a session makes such a package call, the package is reinstantiated for the session without error.

Note: Oracle has been optimized to not return this message to the session calling the package that it invalidated. Thus, in the example above, session S would receive this message the first time it called package P2, but would not receive it when calling P1.

In most production environments, DDL operations that can cause invalidations are usually performed during inactive working hours; therefore, this situation might not be a problem for end-user applications. However, if package specification or body invalidations are common in your system during working hours, you might want to code your applications to detect for this error when package calls are made. For example, the user-side application might reinitialize any user-side state that depends on any session's package state (that was lost) and reissue the package call.

Remote Dependencies

Dependencies among PL/SQL library units (packages, stored procedures, and stored functions) can be handled in two ways:

Timestamps

If timestamps are used to handle dependencies among PL/SQL library units, whenever you alter a library unit or a relevant schema object all of its dependent units are marked as invalid and must be recompiled before they can be executed.

Each library unit carries a timestamp that is set by the server when the unit is created or recompiled. Figure 10-1 demonstrates this graphically. Procedures P1 and P2 call stored procedure P3. Stored procedure P3 references table T1. In this example, each of the procedures is dependent on table T1. P3 depends upon T1 directly, while P1 and P2 depend upon T1 indirectly.

Figure 10-1: Dependency Relationships

If P3 is altered, P1 and P2 are marked as invalid immediately if they are on the same server as P3. The compiled states of P1 and P2 contain records of the timestamp of P3. So if the procedure P3 is altered and recompiled, the timestamp on P3 no longer matches the value that was recorded for P3 during the compilation of P1 and P2.

If P1 and P2 are on a client system, or on another Oracle Server in a distributed environment, the timestamp information is used to mark them as invalid at runtime.

Disadvantages of the Timestamp Model

The disadvantage of this dependency model is that is unnecessarily restrictive. Recompilation of dependent objects across the network are often performed when not strictly necessary, leading to performance degradation.

Furthermore, on the client side, the timestamp model can lead to situations that block an application from running at all, if the client-side application is built using PL/SQL version 2. (Earlier releases of tools such as Oracle Forms that used PL/SQL version 1 on the client side did not use this dependency model, since PL/SQL version 1 had no support for stored procedures.)

For releases of Oracle Forms that are integrated with PL/SQL version 2 on the client side, the timestamp model can present problems. First of all, during the installation of the application, the application is rendered invalid unless the client-side PL/SQL procedures that it uses are recompiled at the client site. Also, if a client-side procedure depends on a server procedure, and the server procedure is changed or automatically recompiled, the client-side PL/SQL procedure must then be recompiled. Yet in many application environments (such as Forms runtime applications), there is no PL/SQL compiler available on the client. This blocks the application from running at all. The client application developer must then redistribute new versions of the application to all customers.

Signatures

To alleviate some of the problems with the timestamp-only dependency model, Oracle provides the additional capability of remote dependencies using signatures. The signature capability affects only remote dependencies. Local (same server) dependencies are not affected, as recompilation is always possible in this environment.

The signature of a subprogram contains information about the

Note: Only the types and modes of parameters are significant. The name of the parameter does not affect the signature.

The user has control over whether signatures or timestamps govern remote dependencies. See "Controlling Remote Dependencies" on page 10-21 for more information. If the signature dependency model is in effect, a dependency on a remote library unit causes an invalidation of the dependent unit if the dependent unit contains a call to a subprogram in the parent unit, and the signature of this subprogram has been changed in an incompatible manner.

For example, consider a procedure GET_EMP_NAME stored on a server BOSTON_SERVER. The procedure is defined as

CREATE OR REPLACE PROCEDURE get_emp_name (

                emp_number   IN NUMBER,

                hire_date   OUT VARCHAR2,

                emp_name    OUT VARCHAR2) AS

BEGIN

    SELECT ename, to_char(hiredate, 'DD-MON-YY')

        INTO emp_name, hire_date

        FROM emp

        WHERE empno = emp_number;

END;

When GET_EMP_NAME is compiled on the BOSTON_SERVER, its signature as well as its timestamp is recorded.

Now assume that on another server, in California, some PL/SQL code calls GET_EMP_NAME identifying it using a DB link called BOSTON_SERVER, as follows:

CREATE OR REPLACE PROCEDURE print_ename (

      emp_number IN NUMBER) AS

    hire_date    VARCHAR2(12);

    ename        VARCHAR2(10);

BEGIN

    get_emp_name@BOSTON_SERVER(

        emp_number, hire_date, ename);

    dbms_output.put_line(ename);

    dbms_output.put_line(hiredate);

END;

When this California server code is compiled, the following actions take place:

At runtime, during the remote procedure call from the California server to the Boston server, the recorded signature of GET_EMP_NAME that was saved in the compiled state of PRINT_ENAME gets sent across to the Boston server., regardless of whether there were any changes or not.

If the timestamp dependency mode is in effect, a mismatch in timestamps causes an error status to be returned to the calling procedure.

However, if the signature mode is in effect, any mismatch in timestamps is ignored, and the recorded signature of GET_EMP_NAME in the compiled state of PRINT_ENAME on the California server is compared with the current signature of GET_EMP_NAME on the Boston server. If they match, the call succeeds. If they do not match, an error status is returned to the PRINT_NAME procedure.

Note that the GET_EMP_NAME procedure on the Boston server could have been changed. Or, its timestamp could be different from that recorded in the PRINT_NAME procedure on the California server, due to, for example, the installation of a new release of the server. As long as the signature remote dependency mode is in effect on the California server, a timestamp mismatch does not cause an error when GET_EMP_NAME is called.

What Is a Signature?

A signature is associated with each compiled stored library unit. It identifies the unit using the following criteria:

When Does a Signature Change?

Datatypes

A signature changes when you change from one class of datatype to another. Within each datatype class, there can be several types. Changing a parameter datatype from one type to another within a class does not cause the signature to change.

Table 10-2 shows the classes of types.

Table 10-2: Datatype Classes

Varchar Types:  

Number Types:  

VARCHAR2  

NUMBER  

VARCHAR  

INTEGER  

STRING  

INT  

LONG  

SMALLINT  

ROWID  

DECIMAL  

Character Types:  

DEC  

CHARACTER  

REAL  

CHAR  

FLOAT  

Raw Types:  

NUMERIC  

RAW  

DOUBLE PRECISION  

LONG RAW  

 

Integer Types:  

Date Type:  

BINARY_INTEGER  

DATE  

PLS_INTEGER  

 

BOOLEAN  

MLS Label Type:  

NATURAL  

MLSLABEL  

POSITIVE  

 

POSITIVEN  

 

NATURALN  

 

Modes

Changing to or from an explicit specification of the default parameter mode IN does not change the signature of a subprogram. For example, changing

PROCEDURE P1 (param1 NUMBER);

to

PROCEDURE P1 (param1 IN NUMBER);

does not change the signature. Any other change of parameter mode does change the signature.

Default Parameter Values

Changing the specification of a default parameter value does not change the signature. For example, procedure P1 has the same signature in the following two examples:

PROCEDURE P1 (param1 IN NUMBER := 100);

PROCEDURE P1 (param1 IN NUMBER := 200);

An application developer who requires that callers get the new default value must recompile the called procedure, but no signature-based invalidation occurs when a default parameter value assignment is changed.

Examples of Signatures

In the GET_EMP_NAME procedure defined on page 10-5, if the procedure body is changed to

BEGIN

-- date format model changes

    SELECT ename, to_char(hiredate, 'DD/MON/YYYY')

        INTO emp_name, hire_date

        FROM emp

        WHERE empno = emp_number;

END;

then the specification of the procedure has not changed, and so its signature has not changed.

But if the procedure specification is changed to

CREATE OR REPLACE PROCEDURE get_emp_name (

                emp_number  IN NUMBER,

                hire_date   OUT DATE,

                emp_name    OUT VARCHAR2) AS

and the body is changed accordingly, then the signature changes, because the parameter HIRE_DATE has a different datatype.

However, if the name of that parameter changes to WHEN_HIRED, and the datatype remains VARCHAR2, and the mode remains OUT, then the signature does not change. Changing the name of a formal parameter does not change the signature of the unit.

Consider the following example:

CREATE OR REPLACE PACKAGE emp_package AS

    TYPE emp_data_type IS RECORD (

        emp_number NUMBER,

        hire_date  VARCHAR2(12),

        emp_name   VARCHAR2(10));

    PROCEDURE get_emp_data

        (emp_data IN OUT emp_data_type);

END;


CREATE OR REPLACE PACKAGE BODY emp_package AS

    PROCEDURE get_emp_data

        (emp_data IN OUT emp_data_type) IS

BEGIN

    SELECT empno, ename, to_char(hiredate, 'DD/MON/YY')

        INTO emp_data

        FROM emp

        WHERE empno = emp_data.emp_number;

END;

If the package specification is changed so that the record's field names are changed, but the types remain the same, this does not affect the signature. For example, the following package specification has the same signature as the previous package specification example:

CREATE OR REPLACE PACKAGE emp_package AS

    TYPE emp_data_type IS RECORD (

        emp_num    NUMBER,         -- was emp_number

        hire_dat   VARCHAR2(12),   --was hire_date

        empname    VARCHAR2(10));  -- was emp_name

    PROCEDURE get_emp_data

        (emp_data IN OUT emp_data_type);

END;

Changing the name of the type of a parameter does not cause a change in the signature if the type remains the same as before. For example, the following package specification for EMP_PACKAGE is the same as the first one on page 10-20:

CREATE OR REPLACE PACKAGE emp_package AS

    TYPE emp_data_record_type IS RECORD (

        emp_number NUMBER,

        hire_date  VARCHAR2(12),

        emp_name   VARCHAR2(10));

    PROCEDURE get_emp_data

        (emp_data IN OUT emp_data_record_type);

END;

Controlling Remote Dependencies

Whether the timestamp or the signature dependency model is in effect is controlled by the dynamic initialization parameter REMOTE_DEPENDENCIES_MODE.

If the initialization parameter file contains the specification

REMOTE_DEPENDENCIES_MODE = TIMESTAMP

and this is not explicitly overridden dynamically, then only timestamps are used to resolve dependencies.

If the initialization parameter file contains the parameter specification

REMOTE_DEPENDENCIES_MODE = SIGNATURE

and this not explicitly overridden dynamically, then signatures are used to resolve dependencies.

You can alter the mode dynamically by using the DDL commands

ALTER SESSION SET REMOTE_DEPENDENCIES_MODE = 

    {SIGNATURE | TIMESTAMP}

to alter the dependency model for the current session, or

ALTER SYSTEM SET REMOTE_DEPENDENCIES_MODE = 

    {SIGNATURE | TIMESTAMP}

to alter the dependency model on a system-wide basis after startup.

If the REMOTE_DEPENDENCIES_MODE parameter is not specified, either in the INIT.ORA parameter file, or using the ALTER SESSION or ALTER SYSTEM DDL commands, TIMESTAMP is the default value. So, unless you explicitly use the REMOTE_DEPENDENCIES_MODE parameter, or the appropriate DDL command, your server is operating using the timestamp dependency model.

When you use REMOTE_DEPENDENCIES_MODE=SIGNATURE you should be aware of the following:

Dependency Resolution

When REMOTE_DEPENDENCIES_MODE = TIMESTAMP (the default value), dependencies among library units are handled by comparing timestamps at runtime. If the timestamp of a called remote procedure does not match the timestamp of the called procedure, the calling (dependent) unit is invalidated, and must be recompiled. In this case, if there is no local PL/SQL compiler, the calling application cannot proceed.

In the timestamp dependency mode, signatures are not compared. If there is a local PL/SQL compiler, recompilation happens automatically when the calling procedure is executed.

When REMOTE_DEPENDENCIES_MODE = SIGNATURE, the recorded timestamp in the calling unit is first compared to the current timestamp in the called remote unit. If they match, then the call proceeds normally. If the timestamps do not match, then the signature of the called remote subprogram, as recorded in the calling subprogram, is compared with the current signature of the called subprogram. If they do not match, using the criteria described in the section "What Is a Signature?" on page 10-18, then an error is returned to the calling session.

Suggestions for Managing Dependencies

Oracle recommends that you follow these guidelines for setting the REMOTE_DEPENDENCIES_MODE parameter:

Cursor Variables

Cursor variables are references to cursors. A cursor is a static object; a cursor variable is a pointer to a cursor. Since cursor variables are pointers, they can be passed and returned as parameters to procedures and functions. A cursor variable can also refer to ("point to") different cursors in its lifetime.

Some additional advantages of cursor variables are

See the PL/SQL User's Guide and Reference for a complete discussion of cursor variables.

Declaring and Opening Cursor Variables

You normally allocate memory for a cursor variable in the client application, using the appropriate ALLOCATE command. In Pro*C, you use the EXEC SQL ALLOCATE <cursor_name> command. In the OCI, you use the Cursor Data Area.

You can also use cursor variables in applications that run entirely in a single server session. You can declare cursor variables in PL/SQL subprograms, open them, and use them as parameters for other PL/SQL subprograms.

Examples of Cursor Variables

This section includes several examples of cursor variable usage in PL/SQL. For additional cursor variable examples that use the programmatic interfaces, see the following manuals:

Fetching Data

The following package defines a PL/SQL cursor variable type EMP_VAL_CV_TYPE, and two procedures. The first procedure opens the cursor variable, using a bind variable in the WHERE clause. The second procedure (FETCH_EMP_DATA) fetches rows from the EMP table using the cursor variable.

CREATE OR REPLACE PACKAGE emp_data AS



  TYPE emp_val_cv_type IS REF CURSOR RETURN emp%ROWTYPE;



  PROCEDURE open_emp_cv (emp_cv      IN OUT emp_val_cv_type,

                         dept_number     IN INTEGER); 

  PROCEDURE fetch_emp_data (emp_cv       IN emp_val_cv_type,

                            emp_row     OUT emp%ROWTYPE);



END emp_data;



CREATE OR REPLACE PACKAGE BODY emp_data AS



  PROCEDURE open_emp_cv (emp_cv      IN OUT emp_val_cv_type,

                         dept_number     IN INTEGER) IS

  BEGIN

    OPEN emp_cv FOR SELECT * FROM emp WHERE deptno = dept_number;

  END open_emp_cv;



  PROCEDURE fetch_emp_data (emp_cv       IN emp_val_cv_type,

                            emp_row     OUT emp%ROWTYPE) IS

  BEGIN

    FETCH emp_cv INTO emp_row;

  END fetch_emp_data;

END emp_data;

The following example shows how you can call the EMP_DATA package procedures from a PL/SQL block:

DECLARE

-- declare a cursor variable

  emp_curs emp_data.emp_val_cv_type;



  dept_number dept.deptno%TYPE;

  emp_row emp%ROWTYPE;



BEGIN

  dept_number := 20;



-- open the cursor using a variable

  emp_data.open_emp_cv(emp_curs, dept_number);



-- fetch the data and display it

  LOOP

    emp_data.fetch_emp_data(emp_curs, emp_row);

    EXIT WHEN emp_curs%NOTFOUND;

    DBMS_OUTPUT.PUT(emp_row.ename || '  ');

    DBMS_OUTPUT.PUT_LINE(emp_row.sal);

  END LOOP;

END;

Implementing Variant Records

The power of cursor variables comes from their ability to point to different cursors. In the following package example, a discriminant is used to open a cursor variable to point to one of two different cursors:

CREATE OR REPLACE PACKAGE emp_dept_data AS



  TYPE cv_type IS REF CURSOR;



  PROCEDURE open_cv (cv          IN OUT cv_type,

                     discrim     IN     POSITIVE); 



END emp_dept_data;

/



CREATE OR REPLACE PACKAGE BODY emp_dept_data AS



  PROCEDURE open_cv (cv      IN OUT cv_type,

                     discrim IN     POSITIVE) IS





  BEGIN

    IF discrim = 1 THEN

      OPEN cv FOR SELECT * FROM emp WHERE sal > 2000;

    ELSIF discrim = 2 THEN

      OPEN cv FOR SELECT * FROM dept;

    END IF;

  END open_cv;



END emp_dept_data;

You can call the OPEN_CV procedure to open the cursor variable and point it to either a query on the EMP table or on the DEPT table. How would you use this? The following PL/SQL block shows that you can fetch using the cursor variable, then use the ROWTYPE_MISMATCH predefined exception to handle either fetch:

DECLARE

  emp_rec  emp%ROWTYPE;

  dept_rec dept%ROWTYPE;

  cv       emp_dept_data.cv_type;



BEGIN

  emp_dept_data.open_cv(cv, 1); -- open CV for EMP fetch

  FETCH cv INTO dept_rec;       -- but fetch into DEPT record

                                -- which raises ROWTYPE_MISMATCH

  DBMS_OUTPUT.PUT(dept_rec.deptno);

  DBMS_OUTPUT.PUT_LINE('  ' || dept_rec.loc);



EXCEPTION

  WHEN ROWTYPE_MISMATCH THEN

    BEGIN

      DBMS_OUTPUT.PUT_LINE

           ('Row type mismatch, fetching EMP data...');

      FETCH cv into emp_rec;

      DBMS_OUTPUT.PUT(emp_rec.deptno);

      DBMS_OUTPUT.PUT_LINE('  ' || emp_rec.ename);

    END;

END;

Hiding PL/SQL Code

You can deliver your stored procedures in object code format using the PL/SQL Wrapper. Wrapping your PL/SQL code hides your application internals. To run the PL/SQL Wrapper, enter the WRAP command at your system prompt using the following syntax:

WRAP INAME=input_file [ONAME=ouput_file]

For complete instructions on using the PL/SQL Wrapper, see the PL/SQL User's Guide and Reference.

Error Handling

Oracle allows user-defined errors in PL/SQL code to be handled so that user-specified error numbers and messages are returned to the client application. Once received, the client application can handle the error based on the user-specified error number and message returned by Oracle.

User-specified error messages are returned using the RAISE_APPLICATION_ERROR procedure:

RAISE_APPLICATION_ERROR(error_number, 'text', keep_error_stack)

This procedure terminates procedure execution, rolls back any effects of the procedure, and returns a user-specified error number and message (unless the error is trapped by an exception handler). ERROR_NUMBER must be in the range of -20000 to -20999. Error number -20000 should be used as a generic number for messages where it is important to relay information to the user, but having a unique error number is not required. TEXT must be a character expression, 2 Kbytes or less (longer messages are ignored). KEEP_ERROR_STACK can be TRUE, if you want to add the error to any already on the stack, or FALSE, if you want to replace the existing errors. By default, this option is FALSE.

Attention: Some of the Oracle-supplied packages, such as DBMS_OUTPUT, DBMS_DESCRIBE, and DBMS_ALERT, use application error numbers in the range -20000 to -20005. See the descriptions of these packages for more information.

The RAISE_APPLICATION_ERROR procedure is often used in exception handlers or in the logic of PL/SQL code. For example, the following exception handler selects the string for the associated user-defined error message and calls the RAISE_APPLICATION_ERROR procedure:

...

WHEN NO_DATA_FOUND THEN

   SELECT error_string INTO message

   FROM error_table,

   V$NLS_PARAMETERS V

   WHERE error_number = -20101 AND LANG = v.value AND

      v.name = "NLS_LANGUAGE";

   raise_application_error(-20101, message);

...

Several examples earlier in this chapter also demonstrate the use of the RAISE_APPLICATION_ERROR procedure. The next section has an example of passing a user-specified error number from a trigger to a procedure. For information on exception handling when calling remote procedures, see "Handling Errors in Remote Procedures" on page 10-31.

Declaring Exceptions and Exception Handling Routines

User-defined exceptions are explicitly defined and signaled within the PL/SQL block to control processing of errors specific to the application. When an exception is raised (signaled), the normal execution of the PL/SQL block stops and a routine called an exception handler is invoked. Specific exception handlers can be written to handle any internal or user-defined exception.

Application code can check for a condition that requires special attention using an IF statement. If there is an error condition, two options are available:

You can also define an exception handler to handle user-specified error messages. For example, Figure 10-2 illustrates

Declare a user-defined exception in a procedure or package body (private exceptions) or in the specification of a package (public exceptions). Define an exception handler in the body of a procedure (standalone or package).

Figure 10-2: Exceptions and User-Defined Errors

Unhandled Exceptions

In database PL/SQL program units, an unhandled user-error condition or internal error condition that is not trapped by an appropriate exception handler causes the implicit rollback of the program unit. If the program unit includes a COMMIT statement before the point at which the unhandled exception is observed, the implicit rollback of the program unit can only be completed back to the previous commit.

Additionally, unhandled exceptions in database-stored PL/SQL program units propagate back to client-side applications that call the containing program unit. In such an application, only the application program unit call is rolled back (not the entire application program unit) because it is submitted to the database as a SQL statement.

If unhandled exceptions in database PL/SQL program units are propagated back to database applications, the database PL/SQL code should be modified to handle the exceptions. Your application can also trap for unhandled exceptions when calling database program units and handle such errors appropriately. For more information, see "Handling Errors in Remote Procedures" on page 10-31.

Handling Errors in Distributed Queries

You can use a trigger or stored procedure to create a distributed query. This distributed query is decomposed by the local Oracle into a corresponding number of remote queries, which are sent to the remote nodes for execution. The remote nodes execute the queries and send the results back to the local node. The local node then performs any necessary post-processing and returns the results to the user or application.

If a portion of a distributed statement fails, for example, due to an integrity constraint violation, Oracle returns error number ORA-02055. Subsequent statements or procedure calls return error number ORA-02067 until a rollback or rollback to savepoint is issued.

You should design your application to check for any returned error messages that indicate that a portion of the distributed update has failed. If you detect a failure, you should rollback the entire transaction (or rollback to a savepoint) before allowing the application to proceed.

Handling Errors in Remote Procedures

When a procedure is executed locally or at a remote location, four types of exceptions can occur:

When using local procedures, all of these messages can be trapped by writing an exception handler, such as shown in the following example:

EXCEPTION

    WHEN ZERO_DIVIDE THEN

    /* ...handle the exception */

Notice that the WHEN clause requires an exception name. If the exception that is raised does not have a name, such as those generated with RAISE_APPLICATION_ERROR, one can be assigned using PRAGMA_EXCEPTION_INIT, as shown in the following example:

DECLARE

    ...

    null_salary EXCEPTION;

    PRAGMA EXCEPTION_INIT(null_salary, -20101);

BEGIN

    ...

    RAISE_APPLICATION_ERROR(-20101, 'salary is missing');

    ...

EXCEPTION

    WHEN null_salary THEN

        ...

When calling a remote procedure, exceptions are also handled by creating a local exception handler. The remote procedure must return an error number to the local, calling procedure, which then handles the exception as shown in the previous example. Because PL/SQL user-defined exceptions always return ORA-06510 to the local procedure, these exceptions cannot be handled. All other remote exceptions can be handled in the same manner as local exceptions.

Compile Time Errors

When you use SQL*Plus to submit PL/SQL code, and the code contains errors, you receive notification that compilation errors have occurred, but no immediate indication of what the errors are. For example, if you submit a standalone (or stored) procedure PROC1 in the file proc1.sql as follows:

SVRMGR> @proc1

and there are one or more errors in the code, you receive a notice such as

MGR-00072: Warning: Procedure PROC1 created with compilation errors

In this case, use the SHOW ERRORS command in SQL*Plus to get a list of the errors that were found. SHOW ERRORS with no argument lists the errors from the most recent compilation. You can qualify SHOW ERRORS using the name of a procedure, function, package, or package body:

SQL> SHOW ERRORS PROC1
SQL> SHOW ERRORS PROCEDURE PROC1

See the SQL*Plus User's Guide and Reference for complete information about the SHOW ERRORS command.

Attention: Before issuing the SHOW ERRORS command, use the SET CHARWIDTH command to get long lines on output. The value 132 is usually a good choice:

SET CHARWIDTH 132

For example, assume you want to create a simple procedure that deletes records from the employee table using SQL*Plus:

CREATE PROCEDURE fire_emp(emp_id NUMBER) AS

   BEGIN

      DELETE FROM emp WHER empno = emp_id;

   END

/

Notice that the CREATE PROCEDURE statement has two errors: the DELETE statement has an error (the 'E' is absent from WHERE) and the semicolon is missing after END.

After the CREATE PROCEDURE statement is issued and an error is returned, a SHOW ERRORS statement would return the following lines:

SHOW ERRORS;



ERRORS FOR PROCEDURE FIRE_EMP:

LINE/COL       ERROR

-------------- --------------------------------------------

3/27   PL/SQL-00103: Encountered the symbol "EMPNO" wh. . .

5/0    PL/SQL-00103: Encountered the symbol "END" when . . .

2 rows selected.

Notice that each line and column number where errors were found is listed by the SHOW ERRORS command.

Alternatively, you can query the following data dictionary views to list errors when using any tool or application:

The error text associated with the compilation of a procedure is updated when the procedure is replaced, and deleted when the procedure is dropped.

Original source code can be retrieved from the data dictionary using the following views: ALL_SOURCE, USER_SOURCE, and DBA_SOURCE. See Oracle8 Server Reference Manual for more information about these data dictionary views.

Debugging

You can debug stored procedures and triggers using the DBMS_OUTPUT supplied package. You put PUT and PUT_LINE statements in your code to output the value of variables and expressions to your terminal. See "Output from Stored Procedures and Triggers" on page 12-19 for more information about the DBMS_OUTPUT package.

A more convenient way to debug, if your platform supports it, is to use the Oracle Procedure Builder, which is part of the Oracle Developer/2000 tool set. Procedure Builder lets you execute PL/SQL procedures and triggers in a controlled debugging environment, and you can set breakpoints, list the values of variables, and perform other debugging tasks. See the Oracle Procedure Builder Developer's Guide for more information.

Invoking Stored Procedures

Procedures can be invoked from many different environments. For example:

Some common examples of invoking procedures from within these environments follow. For more information, see "Calling Stored Functions from SQL Expressions" on page 10-41.

A Procedure or Trigger Calling Another Procedure

A procedure or trigger can call another stored procedure. For example, included in the body of one procedure might be the line

. . .

sal_raise(emp_id, 200);

. . .

This line calls the SAL_RAISE procedure. EMP_ID is a variable within the context of the procedure. Note that recursive procedure calls are allowed within PL/SQL; that is, a procedure can call itself.

Interactively Invoking Procedures From Oracle Tools

A procedure can be invoked interactively from an Oracle tool such as SQL*Plus. For example, to invoke a procedure named SAL_RAISE, owned by you, you can use an anonymous PL/SQL block, as follows:

BEGIN

    sal_raise(1043, 200);

END;

Note: Interactive tools such as SQL*Plus require that you follow these lines with a slash (/) to execute the PL/SQL block.

An easier way to execute a block is to use the SQL*Plus command EXECUTE, which effectively wraps BEGIN and END statements around the code you enter. For example:

EXECUTE sal_raise(1043, 200);

Some interactive tools allow session variables to be created. For example, when using SQL*Plus, the following statement creates a session variable:

VARIABLE assigned_empno NUMBER

Once defined, any session variable can be used for the duration of the session. For example, you might execute a function and capture the return value using a session variable:

EXECUTE :assigned_empno := hire_emp('JSMITH', 'President', \

   1032, SYSDATE, 5000, NULL, 10);

PRINT assigned_empno;

ASSIGNED_EMPNO

--------------

          2893

See the SQL*Plus User's Guide and Reference for SQL*Plus information. See your tools manual for information about performing similar operations using your development tool.

Calling Procedures within 3GL Applications

A 3GL database application such as a precompiler or OCI application can include a call to a procedure within the code of the application.

To execute a procedure within a PL/SQL block in an application, simply call the procedure. The following line within a PL/SQL block calls the FIRE_EMP procedure:

fire_emp(:empno);

In this case, :EMPNO is a host (bind) variable within the context of the application.

To execute a procedure within the code of a precompiler application, you must use the EXEC call interface. For example, the following statement calls the FIRE_EMP procedure in the code of a precompiler application:

EXEC SQL EXECUTE

   BEGIN

      fire_emp(:empno);

   END;

END-EXEC;

:EMPNO is a host (bind) variable.

For more information about calling PL/SQL procedures from within 3GL applications, see the following manuals:

Name Resolution When Invoking Procedures

References to procedures and packages are resolved according to the algorithm described in "Name Resolution in SQL Statements" on page 4-44.

Privileges Required to Execute a Procedure

If you are the owner of a standalone procedure or package, you can execute the standalone procedure or packaged procedure, or any public procedure or packaged procedure at any time, as described in the previous sections. If you want to execute a standalone or packaged procedure owned by another user, the following conditions apply:

Attention: A stored subprogram or package executes in the privilege domain of the owner of the procedure. The owner must have been explicitly granted the necessary object privileges to all objects referenced within the body of the code.

Specifying Values for Procedure Arguments

When you invoke a procedure, specify a value or parameter for each of the procedure's arguments. Identify the argument values using either of the following methods, or a combination of both:

For example, these statements each call the procedure UPDATE_SAL to increase the salary of employee number 7369 by 500:

sal_raise(7369, 500);



sal_raise(sal_incr=>500, emp_id=>7369);



sal_raise(7369, sal_incr=>500);

The first statement identifies the argument values by listing them in the order in which they appear in the procedure specification.

The second statement identifies the argument values by name and in an order different from that of the procedure specification. If you use argument names, you can list the arguments in any order.

The third statement identifies the argument values using a combination of these methods. If you use a combination of order and argument names, values identified in order must precede values identified by name.

If you have used the DEFAULT option to define default values for IN parameters to a subprogram (see the PL/SQL User's Guide and Reference), you can pass different numbers of actual parameters to the 1subprogram, accepting or overriding the default values as you please. If an actual value is not passed, the corresponding default value is used. If you want to assign a value to an argument that occurs after an omitted argument (for which the corresponding default is used), you must explicitly designate the name of the argument, as well as its value.

Invoking Remote Procedures

Invoke remote procedures using an appropriate database link and the procedure's name. The following SQL*Plus statement executes the procedure FIRE_EMP located in the database pointed to by the local database link named NY:

EXECUTE fire_emp@NY(1043);

For information on exception handling when calling remote procedures, see page 10-31.

Remote Procedure Calls and Parameter Values

You must explicitly pass values to all remote procedure parameters even if there are defaults. You cannot access remote package variables and constants.

Referencing Remote Objects

Remote objects can be referenced within the body of a locally defined procedure. The following procedure deletes a row from the remote employee table:

CREATE PROCEDURE fire_emp(emp_id NUMBER) IS

BEGIN

    DELETE FROM emp@sales WHERE empno = emp_id;

END;

The list below explains how to properly call remote procedures, depending on the calling environment.

Here, LOCAL_PROCEDURE is defined as in the first item of this list.

Note: Synonyms can be used to create location transparency for the associated remote procedures.

Warning: Unlike stored procedures, which use compile-time binding, runtime binding is used when referencing remote procedures. The user account to which you connect depends on the database link.

All calls to remotely stored procedures are assumed to perform updates; therefore, this type of referencing always requires two-phase commit of that transaction (even if the remote procedure is read-only). Furthermore, if a transaction that includes a remote procedure call is rolled back, the work done by the remote procedure is also rolled back. A procedure called remotely cannot execute a COMMIT, ROLLBACK, or SAVEPOINT statement.

A distributed update modifies data on two or more nodes. A distributed update is possible using a procedure that includes two or more remote updates that access data on different nodes. Statements in the construct are sent to the remote nodes and the execution of the construct succeeds or fails as a unit. If part of a distributed update fails and part succeeds, a rollback (of the entire transaction or to a savepoint) is required to proceed. Consider this when creating procedures that perform distributed updates.

Pay special attention when using a local procedure that calls a remote procedure. If a timestamp mismatch is found during execution of the local procedure, the remote procedure is not executed and the local procedure is invalidated.

Synonyms for Procedures and Packages

Synonyms can be created for standalone procedures and packages to

When a privileged user needs to invoke a procedure, an associated synonym can be used. Because the procedures defined within a package are not individual objects (that is, the package is the object), synonyms cannot be created for individual procedures within a package.




Prev

Next
Oracle
Copyright © 1997 Oracle Corporation.
All Rights Reserved.

Library

Product

Contents

Index