ORACLE
ORACLE
Method 4 Dynamic
SQL with Native
Dynamic SQL
Steven Feuerstein
In this article, Steven Feuerstein explores Method 4 Dynamic SQL and its uses.
I
T’S so easy in our chosen professional careers to fall into a veritable
perdition of acronyms and jargon. Some of my non-tekkie friends regularly
castigate me for turning every concept or name into three-letter shorthand.
Why do I do this? Why do technoids around the world do this? Probably
because we live in a highly abstracted world that’s not very easily explained
to anyone, including those who dreamed up the world to begin with. So Sample Issue
rather than figure out how to explain our thinking clearly and simply, we use
“brute force” to convince others that 1) we know what we’re talking about, 1 Method 4 Dynamic SQL
and 2) they should obviously understand us, else there’s something wrong with Native Dynamic SQL
with them. Steven Feuerstein
Inexcusable behavior, any way you look at it. Let me give you an example.
8 Transaction, Heal Thyself!
Here’s one way to describe the article you’re about to read: Part 2
Darryl Hurley
In this article, I will describe the characteristics of Method 4 Dynamic SQL
11 Oracle9i R2 Buffer
(M4) and explore the challenges presented when attempting to implement
Cache Advisory
an M4 statement following normal procedures with Native Dynamic James F. Koopmann
SQL (NDS). I will then introduce dynamic PL/SQL and demonstrate an
NDS-based solution to the M4 problem that at times involves two levels of 16 Downloads
dynamic statement evaluation.
If you ever read gobbledygook like that, you should never say, “Wow, that
person sure is smart.” You should instead say: “I really wonder how well that
Indicates accompanying files are available online at
Continues on page 3 www.oracleprofessionalnewsletter.com.
D:
GE
A
PA
L
FUL QUEST
Term Explanation
Dynamic SQL SQL statements, including DDL, DML, and queries, whose logic and syntax aren’t determined until your program is
executed. Usually, this means that the user of the program provides the final “bits” of information needed to complete
the SQL. statement.
Bind variable A value that’s provided to the dynamic SQL statement when executed. In general, the PL/SQL engine replaces a
“placeholder” in the dynamic SQL string with the bind variable or specific value.
Method 1 Dynamic SQL A dynamically constructed SQL statement that isn’t a query and doesn’t contain any “bind variables.” Examples: any
DDL statement or an INSERT, UPDATE, or DELETE without any bind variables.
Method 2 Dynamic SQL A dynamically constructed SQL statement that isn’t a query and contains a fixed number of bind variables. This means
that when you write your code, you know that the user might provide one or even six values, but they’ll always provide
the same number of values, in specific places in the SQL statement.
Method 3 Dynamic SQL A dynamically constructed SELECT statement with a fixed number of columns in the select list and a fixed number of
bind variables. The name of the table being queried might vary, but the query will always return one or three or 25 values,
and the WHERE clause will always contain two or seven or 15 placeholders that require bind variables.
Method 4 Dynamic SQL A dynamically constructed SQL statement in which, essentially, anything goes. On Monday, you might need to return six
values in the select list, without needing any bind variables. On Tuesday, you return just three values, but you have two
bind variables. Or you might have an UPDATE statement.
Dynamic PL/SQL A block of code that’s constructed, compiled, and executed at runtime. This isn’t the same thing as constructing and
executing a “CREATE OR REPLACE PROCEDURE” statement. That’s dynamic DDL. Dynamic PL/SQL occurs when you
construct a “BEGIN...END;” block and run that.
DBMS_SQL The built-in or supplied package that has since PL/SQL 7.1 given us the ability to execute dynamically constructed SQL
statements and PL/SQL blocks. It’s one of the slowest and most complex of the supplied packages.
Native Dynamic SQL Native statements in the PL/SQL language (EXECUTE IMMEDIATE and OPEN FOR) that allow you, in Oracle8i and above, to
execute dynamically constructed SQL statements and PL/SQL blocks—without relying on DBMS_SQL. Native Dynamic
SQL is faster and much, much easier to write than DBMS_SQL. Thanks, Oracle!
Line(s) Description
3-9 I execute a cursor FOR loop against the ALL_TAB_COLUMNS, identifying just those columns relevant to the specified table (details not
shown). Using that data, I construct the comma-delimited select list and also a comma-delimited variable list. Note: I don’t show the
naming convention for the variables here, and almost any will do; just make sure that there’s a unique variable for each column.
11-23 I construct and assign a string to the variable my_block. Look closely. I’m putting together a valid PL/SQL block, starting with BEGIN
and ending with, well, END;. I’ve stuffed the EXECUTE IMMEDIATE of the SELECT inside this block. The next few entries explain some
of the nuances.
14 The two single quotes before the keyword SELECT evaluate to one quote when the block is compiled. This quote initiates the dynamic
query inside the EXECUTE IMMEDIATE.
19 I terminate the dynamic query inside the dynamic PL/SQL block with the concatenation of four single quotes before the INTO keyword.
Four single quotes evaluate down to one single quote.
25 I execute the dynamic PL/SQL block. When this line is run, the block is constructed (most notably, the list of variables is put together) and
then compiled. Assuming there’s no compilation error, PL/SQL then executes the block, which in turn constructs and executes the query,
fetching the data into the specified list of variables.
W
HILE resumable statements are a boon to DBAs further within exception handlers, as shown in Listing 1.
and developers alike, they do make one
application concept more complicated:
exception handling. Consider this overly simplistic Listing 1. Trapping ORA-1013 for timeouts.
exception-handling block:
SQL> BEGIN
2 EXECUTE IMMEDIATE 'CREATE TABLE demo ( col1 NUMBER )';
EXCEPTION 3 EXCEPTION
WHEN OTHERS THEN 4 WHEN OTHERS THEN
IF SQLCODE = -01536 THEN 5 IF SQLCODE = -1013 THEN
DBMS_OUTPUT.PUT_LINE('Space Quota Exceeded!'); 6 DBMS_OUTPUT.PUT_LINE('What should I do?');
ELSE 7 ELSE
DBMS_OUTPUT.PUT_LINE('Something Else!'); 8 RAISE;
END IF; 9 END IF;
END; 10 END;
11 /
What should I do?
If the code raises ORA-1536 (space quota exceeded),
this simplified exception handler will display a mundane PL/SQL procedure successfully completed.
SQL> BEGIN
The real exception is indeed re-raised, although
2 EXECUTE IMMEDIATE 'CREATE TABLE demo ( col1 NUMBER )'; some details are lost, such as the tablespace name
3 EXCEPTION
(see Listing 5). But at least a calling program can
4 WHEN OTHERS THEN
5 IF SQLCODE = -30032 THEN determine what went wrong based on the Oracle
6 DBMS_OUTPUT.PUT_LINE('I know what to do?'); error number.
7 ELSE
8 RAISE;
9 END IF;
10 END; Listing 5. The re-raised exception.
11 /
I know what to do?
BEGIN
PL/SQL procedure successfully completed. *
ERROR at line 1:
ORA-01536: space quota exceeded for tablespace ''
The real error can be gleaned by parsing the error ORA-06512: at line 1
ORA-06512: at line 11
stack as demonstrated in Listing 3. ORA-30032: the suspended (resumable) statement has
timed out
ORA-01536: space quota exceeded for tablespace 'USERS'
Listing 3. Exception handler extracting the real error message.
The whole point of this first section has been to
EXCEPTION make it very clear that adding resumable statements to
WHEN OTHERS THEN
IF SQLCODE = -30032 THEN applications requires a lot of thought with regards to
DECLARE exception handling.
v_error_stack VARCHAR2(2000) :=
DBMS_UTILITY.FORMAT_ERROR_STACK; The next section of this article switches gears to deal
BEGIN with failure of another sort in THY—specifically,
v_error_stack := SUBSTR(v_error_stack,
INSTR(v_error_stack,CHR(10))+1,1000); determining whether an attempted fix was successful.
DBMS_OUTPUT.PUT_LINE(v_error_stack);
END;
END IF; Triumph or disappointment?
END; In the first article of this series I assumed all fixes
applied by THY were triumphant in allowing
Now the real error number and message displays: suspended statements to resume. However, plenty
of proverbs and past experiences dissuade me from
ORA-01536: space quota exceeded for tablespace 'USERS'
sticking to this assumption. I think I’ll enhance the
application instead.
But what if the code calling this block is designed
Recall that all sessions registering for resumable
to respond to specific error numbers? An actual
statements find themselves listed in the DBA_
exception throwing ORA-1536 must occur. This can
RESUMABLE view. This view includes a column
be accomplished using Native Dynamic SQL (NDS) to
denoting the current status of the session. Thus, the
re-raise the exception, as revealed in Listing 4.
easiest way to check success or failure is to query its
status in this view. To do this, I need to capture the
Listing 4. Re-raising the real exception. session ID (SID) within the AFTER SUSPEND trigger
and record it in the FIXER_INFO table, as demonstrated
EXCEPTION
in Listing 6.
WHEN OTHERS THEN
IF SQLCODE = -30032 THEN
DECLARE
v_error_stack VARCHAR2(2000) := Listing 6. Gathering session ID (SID) in the AFTER
DBMS_UTILITY.FORMAT_ERROR_STACK;
BEGIN
SUSPEND trigger.
v_error_stack := SUBSTR(v_error_stack,
INSTR(v_error_stack,CHR(10))+1, CURSOR curs_get_sid IS
10000); SELECT sid
v_error_stack := SUBSTR(v_error_stack,4, FROM v$mystat;
INSTR(v_error_stack,':') - 4); v_sid NUMBER;
EXECUTE IMMEDIATE 'DECLARE ' || …
' v_exception EXCEPTION;' || OPEN curs_get_sid;
' PRAGMA EXCEPTION_INIT(v_exception,' || FETCH curs_get_sid INTO v_sid;
v_error_stack || ');' || CLOSE curs_get_sid;
RETURN(v_ret_val);
Even the fastest DBA or automated device requires
END normal_status; more than one second to resolve problems.
A solution is to reset the session’s timeout value
Wasted suspension within exception or error handling routines whenever a
Now that the outcome of a fix can be evaluated within session timeout (ORA-30032) is processed. This requires
THY, it’s time to respond to the outcome—specifically easy access to the original value. One way that can be
when a suspended statement is deemed beyond help. provided is using an application context as created in
Consider this example: Listing 8.
/*---------------------------------------------*/
PROCEDURE set_timeout ( p_timeout NUMBER ) AS
A
S an Oracle DBA, you quickly learn the golden caches defined, which I’m sure you don’t, you’d only take
rule: Disk is slow, memory is fast, and the up 800 bytes.
more information you can keep in memory for Run this query to determine your current setting:
immediate access, the better performance you’ll
experience and less resources you’ll consume. The SQL> SHOW PARAMETER db_cache_advice
NAME TYPE VALUE
complexity comes when determining how much memory -------------------------------- ----------- -----------
you should allocate for Oracle to use. db_cache_advice string ON
What is the buffer cache advisory? To change your current setting, run this:
The buffer cache advisory is an Oracle9i feature that
SQL> ALTER SYSTEM SET db_cache_advice=ON SCOPE=SPFILE;
allows for the gathering of statistics on and the prediction
of using differently sized buffer caches. When this feature
STATISTICS_LEVEL
is turned on, it populates the V$DB_CACHE_ADVICE
Oracle9i has introduced a new initialization parameter
performance view with a row of predicted I/O activity
called STATISTICS_LEVEL. You can use this parameter
information for some 20 sample sizes for each buffer
to set DB_CACHE_ADVICE. Be aware that if you do have
cache in use. This advisory is available for all buffer
a setting in your init.ora or spfile for DB_CACHE_
caches (2K, 4K, 8K, 16K, 32K, KEEP, and RECYCLE
ADVICE already, the STATISTICS_LEVEL parameter
buffer caches).
won’t affect or change this setting. Also note that setting
the STATISTICS_LEVEL will turn on other advisories and
What affects the setting?
statistical collections that you may not want. This
Two Oracle initialization parameters are available to
parameter has three settings and must be set to TYPICAL
configure the advisory—namely, DB_CACHE_ADVICE
or ALL for the DB_CACHE_ADVICE advisory to be
and STATISTICS_LEVEL.
turned on:
• BASIC—Causes no advisories or statistics to
DB_CACHE_ADVICE
be collected.
In order to control the collection of advisory statistics,
• TYPICAL—Causes most of the advisories and
you must set the DB_CACHE_ADVICE parameter to
statistics to be collected.
one of the following values:
• ALL—Causes all of the advisories and statistics
• OFF—Advisory is turned off.
to be collected.
• READY—Advisory is turned off. Previously
collected statistics in V$DB_CACHE_ADVICE
You can check to see whether you have an entry in
are kept intact.
your parameter file if the following SQL returns a value of
• ON—Advisory is turned on.
FALSE in the ISDEFAULT column:
When switched on from any other state, the statistics
SELECT name, value, isdefault FROM v$parameter
in V$DB_CACHE_ADVICE are cleared. The most WHERE NAME ='db_cache_advice';
important thing to realize is that if you start up your
database in the OFF state, or switch to the OFF state, you Run this query to determine your current setting:
Calculate the buffer cache hit ratio for the system The problem with just using the buffer cache hit ratio
Before the buffer cache advisory became available, the in the past was that most DBAs blindly increased the size
staple of sizing the buffer cache was to use a buffer cache of the buffer cache if the hit ratio was low. They’d do this
hit ratio. This ratio was a percentage of how often a block hoping to get an increase in the hit ratio without fully
that’s been requested was found in the buffer cache and understanding the actual amount of physical I/O they
didn’t require physical I/O. The typical methodology was were trying to alleviate. They also just took a guess about
for a DBA to come up with a ballpark estimate of what the size they should increase the buffer cache to. This is
size he thought it should be and then, if he was a smart where Oracle now helps by giving us a tool that helps us
DBA, run a typical workload through the system, take a systematically adjust the buffer cache sizes by real
look at the buffer cache hit ratio, and then adjust the size statistical data. Read on to see how.
if he thought the hit ratio wasn’t adequate.
Here’s the SQL that will give you the hit ratio for each Use of the V$DB_CACHE_ADVICE view
of the individual buffer caches: Now, alongside the buffer cache hit ratio we have a new
facility, the DB_CACHE_ADVICE view. Before running
--# bchitratio.sql the following SQL, there are a couple of things you
set linesize 132
set pagesize 30 should do to make sure your statistics are valid. The first
col buffhit1 for 990.0000 head 'Buffer|HitRatio' thing you should do is clear out the statistics. You can
SELECT name, block_size,
100*(1 - (physical_reads / accomplish this by setting DB_CACHE_ADVICE to
decode((db_block_gets+consistent_gets),
0,1,null,1,(
READY and then to ON. Then you should run a valid
db_block_gets+consistent_gets)))) buffhit1 workload through your system. Then and only then will
FROM v$buffer_pool_statistics;
the following output be valid. Listing 1 shows the SQL
(db_cache_advice.sql) to look at the buffer cache advice
The flaw with the buffer cache hit ratio in
for all buffers.
bchitratio.sql is that it takes into consideration the
Here’s the output generated:
total number of reads and gets from the time you last
bounced your database to the current point in time. It’s Estd Phys Estd Phys
always best to calculate the hit ratio over a period of NAME BLOCK_SIZE Cache Size (MB) Read Factor Reads
------- ---------- --------------- ----------- ------------
time instead of from database startup. Therefore, in DEFAULT 8192 48 2.59 20,822,942
DEFAULT 8192 96 1.77 14,185,093
order to get a valid hit ratio calculation, you need to DEFAULT 8192 144 1.56 12,540,995
capture the actual statistic values before you run your DEFAULT 8192 192 1.43 11,464,624
DEFAULT 8192 240 1.32 10,621,852
workload through the system and then get the ending DEFAULT 8192 288 1.24 9,943,761
DEFAULT 8192 336 1.16 9,328,107
statistics after the workload is done. Let’s see how we DEFAULT 8192 384 1.11 8,938,872
can accomplish this. DEFAULT 8192 432 1.07 8,605,376
DEFAULT 8192 480 1.04 8,325,580
DEFAULT 8192 528 1.01 8,110,005
Calculate the buffer cache hit ratio for a DEFAULT
DEFAULT
8192
8192
544
576
1.00
.98
8,031,154
7,892,752
given workload DEFAULT 8192 624 .96 7,714,677
Here’s the SQL (workload_
bchitratio.sql) for calculating the Listing 1. The SQL to view the buffer cache advice for all buffers.
buffer cache hit ratio over a period
of time, assuming you have tables --# db_cache_advice.sql
col size_for_estimate for 999999 head 'Cache Size (MB)'
beg_buffer_pool_statistics that has col estd_physical_read_factor for 999.90 head 'Estd Phys|Read Factor'
the beginning statistics and col estd_physical_reads for 999,999,999 head 'Estd Phys| Reads'
end_buffer_pool_statistics that has SELECT name,
the ending statistics: block_size,
size_for_estimate,
estd_physical_read_factor,
--# workload_bchitratio.sql estd_physical_reads
set linesize 132 FROM V$DB_CACHE_ADVICE
set pagesize 30 WHERE advice_status = 'ON';
Listing 9. AFTER LOGON trigger calling SET_TIMEOUT. Listing 10. RESET_TIMEOUT procedure in FIXER package.
Pinnacle, A Division of Lawrence Ragan Communications, Inc. ▲ 800-493-4867 x.4209 or 312-960-4100 ▲ Fax 312-960-4106
Now exception and error handling code only needs to Darryl Hurley has been working with Oracle technology for 15 years,
call RESET_TIMEOUT to reset the session’s timeout value. with a significant focus on database administration and PL/SQL
development. His days are spent as the database manager for MDSI
WHEN OTHERS THEN Mobile Data Solutions Inc (www.mdsi-advantex.com), and his spare
IF SQLCODE = -30032 THEN
RESET_TIMEOUT; time is spent writing articles and teaching under the moniker of
handle_exception(… ImpleStrat Solutions (www.implestrat.com). He’s written several articles
for the Oracle Development Tools User Group (www.odtug.com) and
Coming up next time contributed to several Oracle books from O’Reilly & Associates
The next article in this series will flush out the complete (www.ora.com). [email protected] or [email protected].
Downloads
• FEUER.ZIP—Source code to accompany Steven Feuerstein’s • KOOP.ZIP—Source code to accompany James F.
article, “Method 4 Dynamic SQL with Native Dynamic SQL.” Koopmann’s article, “Oracle9i R2 Buffer Cache Advisory.”
Know a clever shortcut? Have an idea for an article for Oracle Professional?
See below for the contact information where you can send your ideas.
Questions? POSTMASTER: Send address changes to Lawrence Ragan Communications, Inc., 316
N. Michigan Ave., Suite 400, Chicago, IL 60601.
Customer Service:
Phone: 800-493-4867 x.4209 or 312-960-4100 Copyright © 2003 by Lawrence Ragan Communications, Inc. All rights reserved. No part
of this periodical may be used or reproduced in any fashion whatsoever (except in the
Fax: 312-960-4106 case of brief quotations embodied in critical articles and reviews) without the prior
Email: [email protected] written consent of Lawrence Ragan Communications, Inc. Printed in the United States
of America.
Editorial: [email protected]
Oracle, Oracle 8i, Oracle 9i, PL/SQL, and SQL*Plus are trademarks or registered trademarks of
Advertising: [email protected] Oracle Corporation. Other brand and product names are trademarks or registered trademarks
of their respective holders. Oracle Professional is an independent publication not affiliated
Pinnacle Web Site: www.pinnaclepublishing.com with Oracle Corporation. Oracle Corporation is not responsible in any way for the editorial
policy or other contents of the publication.
Subscription rates This publication is intended as a general guide. It covers a highly technical and complex
subject and should not be used for making decisions concerning specific products or
applications. This publication is sold as is, without warranty of any kind, either express or
United States: One year (12 issues): $229; two years (24 issues): $389 implied, respecting the contents of this publication, including but not limited to implied
warranties for the publication, performance, quality, merchantability, or fitness for any particular
Other:* One year: $254; two years: $432 purpose. Lawrence Ragan Communications, Inc., shall not be liable to the purchaser or any
other person or entity with respect to any liability, loss, or damage caused or alleged to be
Single issue rate: caused directly or indirectly by this publication. Articles published in Oracle Professional
$27.50 ($32.50 outside United States)* reflect the views of their authors; they may or may not reflect the view of Lawrence Ragan
Communications, Inc. Inclusion of advertising inserts does not constitute an endorsement by
* Funds must be in U.S. currency. Lawrence Ragan Communications, Inc., or Oracle Professional.