home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


2.2 Getting Started with DBMS_SQL

Before you start using DBMS_SQL, you need to make sure that it is installed and that the appropriate users have access to this package. In addition, you should be aware of how privileges are applied to programs that execute dynamic SQL.

2.2.1 Creating the DBMS_SQL Package

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

Given the power, flexibility, and potential impact of dynamic SQL, you may actually want to revoke public access to DBMS_SQL and instead grant EXECUTE privilege to only those users who need to perform dynamic SQL.

To "hide" DBMS_SQL, issue this command from the SYS account:

REVOKE EXECUTE ON DBMS_SQL FROM PUBLIC;

To grant EXECUTE privilege to a specific user, issue this command from SYS:

GRANT EXECUTE ON DBMS_SQL TO whatever_user;

2.2.2 Security and Privilege Issues

Generally, when you run stored code (and all DBMS_* built-in packages are certainly stored in the database!), that code executes under the authority and using the privileges associated with the owner of the code. If this rule were applied to DBMS_SQL, then anyone who had EXECUTE privilege on DBMS_SQL would be able to act as SYS. This is clearly not a viable approach.

When you execute a DBMS_SQL program from within an anonymous block, that program is executed using the privileges of the current schema. If you embed DBMS_SQL programs within a stored program, those dynamic SQL programs will execute using the privileges of the owner of the stored program. DBMS_SQL is, in other words, a "run as user" package, rather than a "run as owner" package. This can lead to a number of complications, discussed in more detail in the "Tips on Using Dynamic SQL" section later in this chapter.

2.2.3 DBMS_SQL Programs

DBMS_SQL is one of the most complex built-in packages, with a large number of programs and data structures defined in the package specification. Table 2.1 summarizes the programs defined in the DBMS_SQL package.


Table 2.1: DBMS_SQL Programs

Name

Description

Use in SQL?

BIND_ARRAY

Binds a specific value to a host array (PL/SQL8 only).

No

BIND_VARIABLE

Binds a specific value to a host variable.

No

CLOSE_CURSOR

Closes the cursor.

No

COLUMN_VALUE

Retrieves a value from the cursor into a local variable.

No

COLUMN_VALUE_LONG

Retrieves a selected part of a LONG value from a cursor's column defined with DEFINE_COLUMN_LONG.

No

DEFINE_ARRAY

Defines an array to be selected from the specified cursor (PL/SQL8 only).

No

DEFINE_COLUMN

Defines a column to be selected from the specified cursor.

No

DEFINE_COLUMN_LONG

Defines a LONG column to be selected from the specified cursor.

No

DESCRIBE_COLUMNS

Describes the columns for a dynamic cursor (PL/SQL8 only).

No

EXECUTE

Executes the cursor.

No

EXECUTE_AND_FETCH

Executes the cursor and fetches its row(s).

No

FETCH_ROWS

Fetches the row(s) from the cursor.

No

IS_OPEN

Returns TRUE if the cursor is open.

No

LAST_ERROR_POSITION

Returns the byte offset in the SQL statement where the error occurred.

No

LAST_ROW_COUNT

Returns the total number of rows fetched from the cursor.

No

LAST_ROW_ID

Returns the ROWID of the last row fetched from the cursor.

No

LAST_SQL_FUNCTION_CODE

Returns the SQL function code for the SQL statement.

No

OPEN_CURSOR

Opens the cursor.

No

PARSE

Parses the specified SQL statement. If the statement is a DDL statement, then the parse also executes the statement.

No

VARIABLE_VALUE

Gets a value of a variable in a cursor.

No

2.2.4 Types of Dynamic SQL

There are four distinct types, or methods, of dynamic SQL that you can execute with the programs of DBMS_SQL; these are listed in Table 2.2 . Familiarity with these methods and the kinds of code you need to write for each will help you use DBMS_SQL most effectively.


Table 2.2: Types of Dynamic SQL

Type

Description

DBMS_SQL Programs Used

Method 1

No queries; just DDL statements and UPDATEs, INSERTs, or DELETEs, which have no bind variables.

EXECUTE

Method 2

No queries; just UPDATEs, INSERTs, or DELETEs, with a fixed number of bind variables.

EXECUTE

Method 3

Queries (SELECT statements) with a fixed numbers of columns and bind variables.

VARIABLE_VALUE

Method 4

Queries (SELECT statements) with a variable numbers of columns and bind variables. In other words, you don't know until runtime how many bind variables there may be.

Same as for Method 3, but the code you must write is much more complex.

The following DDL statement is an example of Method 1 dynamic SQL:

CREATE INDEX emp_ind_1 on emp (sal, hiredate)

And this update statement is also Method 1 dynamic SQL:

UPDATE emp SET sal = 10000 WHERE empno = 1506

Of course, that UPDATE statement also is not very dynamic. If I now add a placeholder to this DML statement (indicated by the colon) so that I do not "hard-code" the employee number, I then have Method 2 dynamic SQL:

UPDATE emp SET sal = 10000 WHERE empno = :employee_id

A call to BIND_VARIABLE will be required for the previous statement to be executed successfully with DBMS_SQL.

A Method 3 dynamic SQL statement is a query with a fixed number of bind variables (or none). This will be the most common type of dynamic SQL you will execute. Here is an example:

SELECT ename, :second_column FROM emp WHERE deptno = :dept_id

In this case, I am leaving until runtime the decision about which column I will retrieve with my query. Now, this statement looks like Method 3 dynamic SQL, but this dynamic stuff can get very tricky. What if I substituted the string "hiredate, sal" for the placeholder "second_column"? I could then have a variable number of columns in the select list, and this would be Method 4 dynamic SQL.

How can you tell the difference? Well, you really can't just by looking at the string. The code, however, will tell. If you do not plan for Method 4 (variable number of columns in the select list, in this case), then your PL/SQL program will fail. It will not issue the right number of calls to DEFINE_COLUMN.

Usually, when you are dealing with Method 4 dynamic SQL, you will have strings that look more like this:

SELECT :select_list FROM emp WHERE :where_clause

Now there can be no doubt: there is no way to know how many columns you are retrieving. So how do you write your PL/SQL program to handle this complexity? Slowly and carefully, with lots of debugging. You will need to write logic to parse strings, locate placeholders, and then call the appropriate DBMS_SQL program.

Very few developers will have to deal with Method 4 dynamic SQL. You can find an example of the kind of code you will have to write in the later section, "Displaying Table Contents with Method 4 Dynamic SQL."

2.2.5 DBMS_SQL Exceptions

The DBMS_SQL defines a single exception in its specification as follows:

DBMS_SQL.

INCONSISTENT_TYPE EXCEPTION;
PRAGMA EXCEPTION_INIT(DBMS_SQL.INCONSISTENT_TYPE, -6562);

This exception can be raised by either the COLUMN_VALUE or the VARIABLE_VALUE procedure if the type of the specified OUT argument is different from the type of the value which is being returned. You can trap this exception and handle it with the following syntax in your exception section:

EXCEPTION
   WHEN DBMS_SQL.INCONSISTENT_TYPE
   THEN
       . . .

You may encounter other exceptions when working with dynamic SQL (in fact, there will be times when you believe that all you can do with DBMS_SQL is raise exceptions). The table on the following page displays some of the most common errors.

Error Number

Description

ORA-00942

Table or view does not exist. You have referenced an object that does not exist in your schema. Remember that when you execute SQL from within a programmatic interface, that SQL is executed under the schema of the owner of the program, not that of the account running the PL/SQL program.

ORA-01001

Invalid cursor. You have tried to use a value which has not been initialized as a DBMS_SQL cursor through a call to OPEN_CURSOR.

ORA-01002

Fetch out of sequence. If you execute FETCH_CURSOR more than once after the cursor's result set is exhausted, you will raise this exception.

ORA-01008

Not all variables bound. You have included a placeholder in your SQL statement string in the form :BINDVAR, but you did not call BIND_VARIABLE to bind a value to that placeholder.

ORA-01027

Bind variables not allowed for data definition operations. You cannot include a bind variable (an identifier with a colon in front of it) in a DDL statement executed dynamically.

ORA-01031

Insufficient privileges. You have tried to execute a SQL statement for which you do not have the appropriate privileges. Remember that when you execute a SQL statement inside a PL/SQL program, all roles are disabled. You will need to have directly granted privileges on your objects to affect them from within PL/SQL and the DBMS_SQL package.

ORA-29255

This occurs with array processing in PL/SQL8. The cursor may not contain both bind and define arrays. For more information, see the section "Array Processing with DBMS_SQL."

2.2.6 DBMS_SQL Nonprogram Elements

DBMS_SQL defines three constants that you use in calls to the PARSE procedure to specify how Oracle handles the SQL statement:

DBMS_SQL.NATIVE CONSTANT INTEGER := 1;
DBMS_SQL.V6 CONSTANT INTEGER := 0;
DBMS_SQL.V7 CONSTANT INTEGER := 2;

The PL/SQL8 version of the DBMS_SQL package also predefines a number of data structures for use in array processing and column describes.

When you want to parse very long SQL statements (in excess of 32Kbytes), you'll need to declare a table based on the DBMS_SQL.VARCHAR2S index-by table TYPE defined as follows:

SUBTYPE VARCHAR2S IS SYS.DBMS_SYS_SQL.VARCHAR2S;

A little investigation reveals that this table is, in turn, defined as:

TYPE VARCHAR2S IS TABLE OF VARCHAR2(256) 
   INDEX BY BINARY_INTEGER;

When you use the DESCRIBE_COLUMNS procedure, you'll need to declare records based on the DBMS_SQL.DESC_REC record TYPE and index-by tables based on the DBMS_SQL.DESC_TAB table TYPE. These are defined as:

TYPE DESC_REC IS RECORD (
   col_type BINARY_INTEGER := 0, /* type of column */
   col_max_len BINARY_INTEGER := 0, /* maximum length of column */
   col_name VARCHAR2(32) := 0, /* name of column */
   col_name_len BINARY_INTEGER := 0, /* length of column name */
   col_schema_name BINARY_INTEGER := 0, 
      /* name of column type schema if an object type */
   col_schema_name_len VARCHAR2(32) := 0, /* length of schema name */
   col_precision BINARY_INTEGER := 0, /* precision if number */
   col_scale BINARY_INTEGER := 0, /* scale if number */
   col_charsetid BINARY_INTEGER := 0, /* character set identifier */
   col_charsetform BINARY_INTEGER := 0, /* character set form */
   col_null_ok BOOLEAN := TRUE /* TRUE if column can be NULL */
   );

TYPE DESC_TAB IS TABLE OF DESC_REC INDEX BY BINARY_INTEGER;

When you perform array processing with the BIND_ARRAY and DEFINE_ARRAY procedures, you will rely on the following predefined index-by tables to set up and manipulate those arrays:

TYPE NUMBER_TABLE IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
TYPE VARCHAR2_TABLE IS TABLE OF VARCHAR2(2000) INDEX BY BINARY_INTEGER;
TYPE DATE_TABLE IS TABLE OF DATE INDEX BY BINARY_INTEGER;
TYPE BLOB_TABLE IS TABLE OF BLOB INDEX BY BINARY_INTEGER;
TYPE CLOB_TABLE IS TABLE OF CLOB INDEX BY BINARY_INTEGER;
TYPE BFILE_TABLE IS TABLE OF BFILE INDEX BY BINARY_INTEGER;

Remember that these index-by tables are also available for your use even when you are not using, for example, the DEFINE_ARRAY procedure. You can still declare your own CLOB index-by tables based on DBMS_SQL.CLOB_TABLE any time you want and under whichever circumstances. This will save you the trouble of defining the table TYPE.

NOTE: BLOB, CLOB, NCLOB, and BFILE are various large object (LOB) datatypes available with PL/SQL8. See the discussion of the DBMS_LOB package in Chapter 8, Managing Large Objects , for more information on manipulating LOBs from within PL/SQL.


Previous: 2.1 Examples of Dynamic SQL Oracle Built-in Packages Next: 2.3 The DBMS_SQL Interface
2.1 Examples of Dynamic SQL Book Index 2.3 The DBMS_SQL Interface

The Oracle Library Navigation

Copyright (c) 2000 O'Reilly & Associates. All rights reserved.

Library Home Oracle PL/SQL Programming, 2nd. Ed. Guide to Oracle 8i Features Oracle Built-in Packages Advanced PL/SQL Programming with Packages Oracle Web Applications Oracle PL/SQL Language Pocket Reference Oracle PL/SQL Built-ins Pocket Reference