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

Guidelines for Dynamic SQL

TYPE NameList IS TABLE OF VARCHAR2(15); enames NameList;

bonus_amt NUMBER := 500; sql_stmt VARCHAR(200);

BEGIN

sql_stmt := 'UPDATE emp SET bonus = :1 RETURNING ename INTO :2'; EXECUTE IMMEDIATE sql_stmt

USING bonus_amt RETURNING BULK COLLECT INTO enames;

END;

/

Example 7–7 Dynamic SQL Inside FORALL Statement

To bind the input variables in a SQL statement, you can use the FORALL statement and USING clause, as shown below. The SQL statement cannot be a query.

DECLARE

TYPE NumList IS TABLE OF NUMBER;

TYPE NameList IS TABLE OF VARCHAR2(15); empnos NumList;

enames NameList; BEGIN

empnos := NumList(1,2,3,4,5); FORALL i IN 1..5

EXECUTE IMMEDIATE

'UPDATE emp SET sal = sal * 1.1 WHERE empno = :1 RETURNING ename INTO :2'

USING empnos(i) RETURNING BULK COLLECT INTO enames;

...

END;

/

Guidelines for Dynamic SQL

This section shows you how to take full advantage of dynamic SQL and how to avoid some common pitfalls.

When to Use or Omit the Semicolon with Dynamic SQL

When building up a single SQL statement in a string, do not include any semicolon at the end.

When building up a PL/SQL anonymous block, include the semicolon at the end of each PL/SQL statement and at the end of the anonymous block.

For example:

BEGIN

EXECUTE IMMEDIATE 'dbms_output.put_line(''No semicolon'')';

EXECUTE IMMEDIATE 'BEGIN dbms_output.put_line(''semicolons''); END;';

END;

Improving Performance of Dynamic SQL with Bind Variables

When you code INSERT, UPDATE, DELETE, and SELECT statements directly in PL/SQL, PL/SQL turns the variables into bind variables automatically, to make the

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

Guidelines for Dynamic SQL

statements work efficiently with SQL. When you build up such statements in dynamic SQL, you need to specify the bind variables yourself to get the same performance.

In the example below, Oracle opens a different cursor for each distinct value of emp_id. This can lead to resource contention and poor performance as each statement is parsed and cached.

CREATE PROCEDURE fire_employee (emp_id NUMBER) AS BEGIN

EXECUTE IMMEDIATE

'DELETE FROM emp WHERE empno = ' || TO_CHAR(emp_id);

END;

/

You can improve performance by using a bind variable, which allows Oracle to reuse the same cursor for different values of emp_id:

CREATE PROCEDURE fire_employee (emp_id NUMBER) AS BEGIN

EXECUTE IMMEDIATE

'DELETE FROM emp WHERE empno = :num' USING emp_id;

END;

/

Passing Schema Object Names As Parameters

Suppose you need a procedure that accepts the name of any database table, then drops that table from your schema. You must build a string with a statement that includes the object names, then use EXECUTE IMMEDIATE to execute the statement:

CREATE PROCEDURE drop_table (table_name IN VARCHAR2) AS BEGIN

EXECUTE IMMEDIATE 'DROP TABLE ' || table_name; END;

/

Use concatenation to build the string, rather than trying to pass the table name as a bind variable through the USING clause.

Using Duplicate Placeholders with Dynamic SQL

Placeholders in a dynamic SQL statement are associated with bind arguments in the USING clause by position, not by name. If you specify a sequence of placeholders like :a, :a, :b, :b, you must include four items in the USING clause. For example, given the dynamic string

sql_stmt := 'INSERT INTO payroll VALUES (:x, :x, :y, :x)';

the fact that the name X is repeated is not significant. You can code the corresponding USING clause with four different bind variables:

EXECUTE IMMEDIATE sql_stmt USING a, a, b, a;

If the dynamic statement represents a PL/SQL block, the rules for duplicate placeholders are different. Each unique placeholder maps to a single item in the USING clause. If the same placeholder appears two or more times, all references to that name correspond to one bind argument in the USING clause. In the following example, all references to the placeholder X are associated with the first bind argument A, and the second unique placeholder Y is associated with the second bind argument B.

Performing SQL Operations with Native Dynamic SQL 7-9

Guidelines for Dynamic SQL

DECLARE

a NUMBER := 4; b NUMBER := 7;

BEGIN

plsql_block := 'BEGIN calc_stats(:x, :x, :y, :x); END;' EXECUTE IMMEDIATE plsql_block USING a, b;

END;

/

Using Cursor Attributes with Dynamic SQL

The SQL cursor attributes %FOUND, %ISOPEN, %NOTFOUND, and %ROWCOUNT work when you issue an INSERT, UPDATE, DELETE, or single-row SELECT statement in dynamic SQL:

EXECUTE IMMEDIATE 'DELETE FROM employees WHERE employee_id > 1000'; rows_deleted := SQL%ROWCOUNT;

Likewise, when appended to a cursor variable name, the cursor attributes return information about the execution of a multi-row query:

OPEN c1 FOR 'SELECT * FROM employees'; FETCH c1 BULK COLLECT INTO rec_tab; rows_fetched := c1%ROWCOUNT;

For more information about cursor attributes, see "Using Cursor Expressions" on page 6-27.

Passing Nulls to Dynamic SQL

The literal NULL is not allowed in the USING clause. To work around this restriction, replace the keyword NULL with an uninitialized variable:

DECLARE

a_null CHAR(1); -- set to NULL automatically at run time BEGIN

EXECUTE IMMEDIATE 'UPDATE emp SET comm = :x' USING a_null; END;

/

Using Database Links with Dynamic SQL

PL/SQL subprograms can execute dynamic SQL statements that use database links to refer to objects on remote databases:

PROCEDURE delete_dept (db_link VARCHAR2, dept_id INTEGER) IS BEGIN

EXECUTE IMMEDIATE 'DELETE FROM departments@' || db_link || ' WHERE deptno = :num' USING dept_id;

END;

/

The targets of remote procedure calls (RPCs) can contain dynamic SQL statements. For example, suppose the following standalone function, which returns the number of rows in a table, resides on the Chicago database:

CREATE FUNCTION row_count (tab_name VARCHAR2) RETURN INTEGER AS rows INTEGER;

BEGIN

7-10 PL/SQL User's Guide and Reference

Guidelines for Dynamic SQL

EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || tab_name INTO rows; RETURN rows;

END;

/

From an anonymous block, you might call the function remotely, as follows:

DECLARE

emp_count INTEGER; BEGIN

emp_count := row_count@chicago('employees'); END;

/

Using Invoker Rights with Dynamic SQL

Dynamic SQL lets you write schema-management procedures that can be centralized in one schema, and can be called from other schemas and operate on the objects in those schemas.

For example, this procedure can drop any kind of database object:

CREATE OR REPLACE PROCEDURE drop_it (kind IN VARCHAR2, name IN VARCHAR2)

AUTHID CURRENT_USER AS

BEGIN

EXECUTE IMMEDIATE 'DROP ' || kind || ' ' || name; END;

/

Let's say that this procedure is part of the HR schema. Without the AUTHID clause, the procedure would always drop objects in the HR schema, regardless of who calls it. Even if you pass a fully qualified object name, this procedure would not have the privileges to make changes in other schemas.

The AUTHID clause lifts both of these restrictions. It lets the procedure run with the privileges of the user that invokes it, and makes unqualified references refer to objects in that user's schema.

For details, see "Using Invoker's Rights Versus Definer's Rights (AUTHID Clause)" on page 8-15.

Using Pragma RESTRICT_REFERENCES with Dynamic SQL

A function called from SQL statements must obey certain rules meant to control side effects. (See "Controlling Side Effects of PL/SQL Subprograms" on page 8-22.) To check for violations of the rules, you can use the pragma RESTRICT_REFERENCES. The pragma asserts that a function does not read or write database tables or package variables. (For more information, See Oracle Database Application Developer's Guide - Fundamentals.)

If the function body contains a dynamic INSERT, UPDATE, or DELETE statement, the function always violates the rules "write no database state" (WNDS) and "read no database state" (RNDS). PL/SQL cannot detect those side-effects automatically, because dynamic SQL statements are checked at run time, not at compile time. In an EXECUTE IMMEDIATE statement, only the INTO clause can be checked at compile time for violations of RNDS.

Performing SQL Operations with Native Dynamic SQL 7-11

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