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

Setting Up Transformation Pipelines with Table Functions

In the example, the PIPE ROW(out_rec) statement pipelines data out of the PL/SQL table function. out_rec is a record, and its type matches the type of an element of the output collection.

The PIPE ROW statement may be used only in the body of pipelined table functions; an error is raised if it is used anywhere else. The PIPE ROW statement can be omitted for a pipelined table function that returns no rows.

A pipelined table function must have a RETURN statement that does not return a value. The RETURN statement transfers the control back to the consumer and ensures that the next fetch gets a NO_DATA_FOUND exception.

Because table functions pass control back and forth to a calling routine as rows areproduced, there is a restriction on combining table functions and PRAGMA AUTONOMOUS_TRANSACTION. If a table function is part of an autonomous transaction, it must COMMIT or ROLLBACK before each PIPE ROW statement, to avoid an error in the calling subprogram.

Oracle has three special SQL datatypes that enable you to dynamically encapsulate and access type descriptions, data instances, and sets of data instances of any other SQL type, including object and collection types. You can also use these three special types to create anonymous (that is, unnamed) types, including anonymous collection types. The types are SYS.ANYTYPE, SYS.ANYDATA, and SYS.ANYDATASET. The

SYS.ANYDATA type can be useful in some situations as a return value from table functions.

See Also: PL/SQL Packages and Types Reference for information about the interfaces to the ANYTYPE, ANYDATA, and ANYDATASET types and about the DBMS_TYPES package for use with these types.

Pipelining Data Between PL/SQL Table Functions

With serial execution, results are pipelined from one PL/SQL table function to another using an approach similar to co-routine execution. For example, the following statement pipelines results from function g to function f:

SELECT * FROM TABLE(f(CURSOR(SELECT * FROM TABLE(g()))));

Parallel execution works similarly except that each function executes in a different process (or set of processes).

Querying Table Functions

Pipelined table functions are used in the FROM clause of SELECT statements. The result rows are retrieved by Oracle iteratively from the table function implementation. For example:

SELECT x.Ticker, x.Price

FROM TABLE(StockPivot( CURSOR(SELECT * FROM StockTable))) x

WHERE x.PriceType='C';

Note: A table function returns a collection. In some cases, such as when the top-level query uses SELECT * and the query refers to a PL/SQL variable or a bind variable, you may need a CAST operator around the table function to specify the exact return type.

11-32 PL/SQL User's Guide and Reference

Setting Up Transformation Pipelines with Table Functions

Optimizing Multiple Calls to Table Functions

Multiple invocations of a table function, either within the same query or in separate queries result in multiple executions of the underlying implementation. By default, there is no buffering or reuse of rows.

For example,

SELECT * FROM TABLE(f(...)) t1, TABLE(f(...)) t2

WHERE t1.id = t2.id;

SELECT * FROM TABLE(f());

SELECT * FROM TABLE(f());

If the function always produces the same result value for each combination of values passed in, you can declare the function DETERMINISTIC, and Oracle automatically buffers rows for it. If the function is not really deterministic, results are unpredictable.

Fetching from the Results of Table Functions

PL/SQL cursors and ref cursors can be defined for queries over table functions. For example:

OPEN c FOR SELECT * FROM TABLE(f(...));

Cursors over table functions have the same fetch semantics as ordinary cursors. REF CURSOR assignments based on table functions do not have any special semantics.

However, the SQL optimizer will not optimize across PL/SQL statements. For example:

DECLARE

r SYS_REFCURSOR; BEGIN

OPEN r FOR SELECT * FROM TABLE(f(CURSOR(SELECT * FROM tab))); SELECT * BULK COLLECT INTO rec_tab FROM TABLE(g(r));

END;

/

does not execute as well as:

SELECT * FROM TABLE(g(CURSOR(SELECT * FROM

TABLE(f(CURSOR(SELECT * FROM tab))))));

This is so even ignoring the overhead associated with executing two SQL statements and assuming that the results can be pipelined between the two statements.

Passing Data with Cursor Variables

You can pass a set of rows to a PL/SQL function in a REF CURSOR parameter. For example, this function is declared to accept an argument of the predefined weakly typed REF CURSOR type SYS_REFCURSOR:

FUNCTION f(p1 IN SYS_REFCURSOR) RETURN ... ;

Results of a subquery can be passed to a function directly:

SELECT * FROM TABLE(f(CURSOR(SELECT empno FROM tab)));

In the example above, the CURSOR keyword is required to indicate that the results of a subquery should be passed as a REF CURSOR parameter.

Tuning PL/SQL Applications for Performance 11-33

Setting Up Transformation Pipelines with Table Functions

A predefined weak REF CURSOR type SYS_REFCURSOR is also supported. With SYS_REFCURSOR, you do not need to first create a REF CURSOR type in a package before you can use it.

To use a strong REF CURSOR type, you still must create a PL/SQL package and declare a strong REF CURSOR type in it. Also, if you are using a strong REF CURSOR type as an argument to a table function, then the actual type of the REF CURSOR argument must match the column type, or an error is generated. Weak REF CURSOR arguments to table functions can only be partitioned using the PARTITION BY ANY clause. You cannot use range or hash partitioning for weak REF CURSOR arguments.

Example 11–11 Example: Using Multiple REF CURSOR Input Variables

PL/SQL functions can accept multiple REF CURSOR input variables:

CREATE FUNCTION g(p1 pkg.refcur_t1, p2 pkg.refcur_t2) RETURN...

PIPELINED ... ;

/

Function g can be invoked as follows:

SELECT * FROM TABLE(g(CURSOR(SELECT employee_id FROM tab),

CURSOR(SELECT * FROM employees));

You can pass table function return values to other table functions by creating a REF CURSOR that iterates over the returned data:

SELECT * FROM TABLE(f(CURSOR(SELECT * FROM TABLE(g(...)))));

Example 11–12 Example: Explicitly Opening a REF CURSOR for a Query

You can explicitly open a REF CURSOR for a query and pass it as a parameter to a table function:

DECLARE

r SYS_REFCURSOR; rec ...;

BEGIN

OPEN r FOR SELECT * FROM TABLE(f(...)); -- Must return a single row result set. SELECT * INTO rec FROM TABLE(g(r));

END;

/

In this case, the table function closes the cursor when it completes, so your program should not explicitly try to close the cursor.

Example 11–13 Example: Using a Pipelined Table Function as an Aggregate Function

A table function can compute aggregate results using the input ref cursor. The following example computes a weighted average by iterating over a set of input rows.

DROP TABLE gradereport;

CREATE TABLE gradereport (student VARCHAR2(30), subject VARCHAR2(30), weight NUMBER, grade NUMBER);

INSERT INTO gradereport VALUES('Mark', 'Physics', 4, 4);

INSERT INTO gradereport VALUES('Mark','Chemistry', 4,3);

INSERT INTO gradereport VALUES('Mark','Maths', 3,3);

INSERT INTO gradereport VALUES('Mark','Economics', 3,4);

11-34 PL/SQL User's Guide and Reference

Setting Up Transformation Pipelines with Table Functions

CREATE OR replace TYPE gpa AS TABLE OF NUMBER;

/

CREATE OR replace FUNCTION weighted_average(input_values sys_refcursor)

RETURN gpa PIPELINED IS grade NUMBER;

total NUMBER := 0; total_weight NUMBER := 0; weight NUMBER := 0;

BEGIN

--The function accepts a ref cursor and loops through all the input rows. LOOP

FETCH input_values INTO weight, grade; EXIT WHEN input_values%NOTFOUND;

--Accumulate the weighted average.

total_weight := total_weight + weight; total := total + grade*weight;

END LOOP;

PIPE ROW (total / total_weight);

-- The function returns a single result. RETURN;

END;

/

show errors;

--The result comes back as a nested table with a single row.

--COLUMN_VALUE is a keyword that returns the contents of a nested table. select weighted_result.column_value from

table( weighted_average( cursor(select weight,grade from gradereport) ) ) weighted_result;

Performing DML Operations Inside Table Functions

To execute DML statements, declare a table function with the AUTONOMOUS_TRANSACTION pragma, which causes the function to execute in a new transaction not shared by other processes:

CREATE FUNCTION f(p SYS_REFCURSOR) return CollType PIPELINED IS PRAGMA AUTONOMOUS_TRANSACTION;

BEGIN NULL; END;

/

During parallel execution, each instance of the table function creates an independent transaction.

Performing DML Operations on Table Functions

Table functions cannot be the target table in UPDATE, INSERT, or DELETE statements. For example, the following statements will raise an error:

UPDATE F(CURSOR(SELECT * FROM tab)) SET col = value;

INSERT INTO f(...) VALUES ('any', 'thing');

However, you can create a view over a table function and use INSTEAD OF triggers to update it. For example:

CREATE VIEW BookTable AS

SELECT x.Name, x.Author

Tuning PL/SQL Applications for Performance 11-35

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