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.
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;
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.
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.
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.
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."
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.
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.
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;
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.
Copyright (c) 2000 O'Reilly & Associates. All rights reserved.