Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
29
Добавлен:
16.04.2013
Размер:
5.97 Mб
Скачать

Calling External Subprograms

There must be at least two paths through a recursive subprogram: one that leads to the recursive call and one that does not. At least one path must lead to a terminating condition. Otherwise, the recursion would go on until PL/SQL runs out of memory and raises the predefined exception STORAGE_ERROR.

Calling External Subprograms

Although PL/SQL is a powerful, flexible language, some tasks are more easily done in another language. Low-level languages such as C are very fast. Widely used languages such as Java have reusable libraries for common design patterns.

You can use PL/SQL call specs to invoke external subprograms written in other languages, making their capabilities and libraries available from PL/SQL.

For example, you can call Java stored procedures from any PL/SQL block, subprogram, or package. Suppose you store the following Java class in the database:

import java.sql.*;

import oracle.jdbc.driver.*; public class Adjuster {

public static void raiseSalary (int empNo, float percent) throws SQLException {

Connection conn = new OracleDriver().defaultConnection(); String sql = "UPDATE emp SET sal = sal * ? WHERE empno = ?"; try {

PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setFloat(1, (1 + percent / 100)); pstmt.setInt(2, empNo);

pstmt.executeUpdate();

pstmt.close();

} catch (SQLException e) {System.err.println(e.getMessage());}

}

}

The class Adjuster has one method, which raises the salary of an employee by a given percentage. Because raiseSalary is a void method, you publish it as a procedure using this call spec:

CREATE PROCEDURE raise_salary (empno NUMBER, pct NUMBER)

AS LANGUAGE JAVA

NAME 'Adjuster.raiseSalary(int, float)';

You might call procedure raise_salary from an anonymous PL/SQL block:

DECLARE

emp_id NUMBER; percent NUMBER;

BEGIN

-- get values for emp_id and percent

raise_salary(emp_id, percent); -- call external subprogram END;

/

External C subprograms are used to interface with embedded systems, solve engineering problems, analyze data, or control real-time devices and processes. External C subprograms extend the functionality of the database server, and move computation-bound programs from client to server, where they execute faster.

Using PL/SQL Subprograms 8-21

Creating Dynamic Web Pages with PL/SQL Server Pages

For more information about Java stored procedures, see Oracle Database Java Developer's Guide. For more information about external C subprograms, see Oracle Database Application Developer's Guide - Fundamentals.

Creating Dynamic Web Pages with PL/SQL Server Pages

PL/SQL Server Pages (PSPs) enable you to develop Web pages with dynamic content. They are an alternative to coding a stored procedure that writes out the HTML code for a web page, one line at a time.

Using special tags, you can embed PL/SQL scripts into HTML source code. The scripts are executed when the pages are requested by Web clients such as browsers. A script can accept parameters, query or update the database, then display a customized page showing the results.

During development, PSPs can act like templates with a static part for page layout and a dynamic part for content. You can design the layouts using your favorite HTML authoring tools, leaving placeholders for the dynamic content. Then, you can write the PL/SQL scripts that generate the content. When finished, you simply load the resulting PSP files into the database as stored procedures.

For more information about creating and using PSPs, see Oracle Database Application Developer's Guide - Fundamentals.

Controlling Side Effects of PL/SQL Subprograms

To be callable from SQL statements, a stored function (and any subprograms called by that function) must obey certain "purity" rules, which are meant to control side effects:

When called from a SELECT statement or a parallelized INSERT, UPDATE, or DELETE statement, the function cannot modify any database tables.

When called from an INSERT, UPDATE, or DELETE statement, the function cannot query or modify any database tables modified by that statement.

When called from a SELECT, INSERT, UPDATE, or DELETE statement, the function cannot execute SQL transaction control statements (such as COMMIT), session control statements (such as SET ROLE), or system control statements (such as ALTER SYSTEM). Also, it cannot execute DDL statements (such as CREATE) because they are followed by an automatic commit.

If any SQL statement inside the function body violates a rule, you get an error at run time (when the statement is parsed).

To check for violations of the rules, you can use the pragma (compiler directive) RESTRICT_REFERENCES. The pragma asserts that a function does not read or write database tables or package variables. For example, the following pragma asserts that packaged function credit_ok writes no database state (WNDS) and reads no package state (RNPS):

CREATE PACKAGE loans AS

FUNCTION credit_ok RETURN BOOLEAN;

PRAGMA RESTRICT_REFERENCES (credit_ok, WNDS, RNPS); END loans;

/

Note: A static INSERT, UPDATE, or DELETE statement always violates WNDS. It also violates RNDS (reads no database state) if it reads any columns. A dynamic INSERT, UPDATE, or DELETE statement always violates WNDS and RNDS.

8-22 PL/SQL User's Guide and Reference

Understanding Subprogram Parameter Aliasing

For full syntax details, see "RESTRICT_REFERENCES Pragma" on page 13-113. For more information about the purity rules, see Oracle Database Application Developer's Guide - Fundamentals.

Understanding Subprogram Parameter Aliasing

To optimize a subprogram call, the PL/SQL compiler can choose between two methods of parameter passing. With the by-value method, the value of an actual parameter is passed to the subprogram. With the by-reference method, only a pointer to the value is passed; the actual and formal parameters reference the same item.

The NOCOPY compiler hint increases the possibility of aliasing (that is, having two different names refer to the same memory location). This can occur when a global variable appears as an actual parameter in a subprogram call and then is referenced within the subprogram. The result is indeterminate because it depends on the method of parameter passing chosen by the compiler.

Example 8–7 Aliasing from Passing Global Variable with NOCOPY Hint

In the example below, procedure ADD_ENTRY refers to varray LEXICON both as a parameter and as a global variable. When ADD_ENTRY is called, the identifiers WORD_LIST and LEXICON point to the same varray.

DECLARE

TYPE Definition IS RECORD ( word VARCHAR2(20), meaning VARCHAR2(200));

TYPE Dictionary IS VARRAY(2000) OF Definition; lexicon Dictionary := Dictionary();

PROCEDURE add_entry (word_list IN OUT NOCOPY Dictionary) IS BEGIN

word_list(1).word := 'aardvark'; lexicon(1).word := 'aardwolf';

END; BEGIN

lexicon.EXTEND; add_entry(lexicon);

dbms_output.put_line(lexicon(1).word); END;

/

The program prints aardwolf if the compiler obeys the NOCOPY hint. The assignment to WORD_LIST is done immediately through a pointer, then is overwritten by the assignment to LEXICON.

The program prints aardvark if the NOCOPY hint is omitted, or if the compiler does not obey the hint. The assignment to WORD_LIST uses an internal copy of the varray, which is copied back to the actual parameter (overwriting the contents of LEXICON) when the procedure ends.

Example 8–8 Aliasing Passing Same Parameter Multiple Times

Aliasing can also occur when the same actual parameter appears more than once in a subprogram call. In the example below, n2 is an IN OUT parameter, so the value of the actual parameter is not updated until the procedure exits. That is why the first put_line prints 10 (the initial value of n) and the third put_line prints 20. However, n3 is a NOCOPY parameter, so the value of the actual parameter is updated immediately. That is why the second put_line prints 30.

Using PL/SQL Subprograms 8-23

Understanding Subprogram Parameter Aliasing

DECLARE

n NUMBER := 10; PROCEDURE do_something (

n1 IN NUMBER,

n2 IN OUT NUMBER,

n3 IN OUT NOCOPY NUMBER) IS BEGIN

n2 := 20;

dbms_output.put_line(n1); -- prints 10 n3 := 30;

dbms_output.put_line(n1); -- prints 30 END;

BEGIN

do_something(n, n, n); dbms_output.put_line(n); -- prints 20

END;

/

Example 8–9 Aliasing from Assigning Cursor Variables to Same Work Area

Because they are pointers, cursor variables also increase the possibility of aliasing. In the following example, after the assignment, emp_cv2 is an alias of emp_cv1; both point to the same query work area. The first fetch from emp_cv2 fetches the third row, not the first, because the first two rows were already fetched from emp_cv1. The second fetch from emp_cv2 fails because emp_cv1 is closed.

PROCEDURE get_emp_data ( emp_cv1 IN OUT EmpCurTyp, emp_cv2 IN OUT EmpCurTyp) IS emp_rec employees%ROWTYPE;

BEGIN

OPEN emp_cv1 FOR SELECT * FROM employees;

emp_cv2 := emp_cv1;

 

FETCH emp_cv1 INTO emp_rec;

-- fetches first row

FETCH emp_cv1 INTO emp_rec;

-- fetches second row

FETCH emp_cv2 INTO emp_rec;

-- fetches third row

CLOSE emp_cv1;

 

FETCH emp_cv2 INTO emp_rec;

-- raises INVALID_CURSOR

END;

 

/

 

8-24 PL/SQL User's Guide and Reference

Соседние файлы в папке Oracle 10g