You are on page 1of 16

Oracle

Solutions for High-End


Oracle® DBAs and Developers Professional

Managing Code in
the Database
Steven Feuerstein
The Oracle data dictionary is a jungle—lushly full of incredible information, but
often with less than clear pathways to your destination. In this article, Steven
Feuerstein shows the way by exploring the use of some of the more useful Oracle
dictionary views.

W
HEN you CREATE OR REPLACE a PL/SQL program, the source
code for that program, along with other representations of that
software, is stored in the database itself and exposed through a
wide range of data dictionary views. This is a tremendous advantage for two May 2005
key reasons: Volume 12, Number 5
• Information about that code is available to you via the SQL language. I
can write queries and even entire PL/SQL programs to read the contents 1 Managing Code in
of these data dictionary views and obtain lots of fascinating and useful the Database
information about my code base. Steven Feuerstein

• The database manages dependencies between your stored objects. For 7 Gently Down the Stream,
example, if a stored function relies on a certain table, and that table’s Part 4
structure is changed, the status of that function is automatically set to Darryl Hurley
INVALID. Recompilation then takes place automatically when someone
12 Getting DDL with
tries to execute that function. DBMS_METADATA
Al Hetzel
This SQL interface to your code base allows you to manage your code
repository—running analyses on your code, documenting what has been 16 May 2005 Downloads

written and changed, and so on. This article reviews some of the commonly
used and useful of these data dictionary views (including some very useful
views added in Oracle9i and Oracle10g), and offers a variety of examples
showing how the views can be applied to answer important questions about Indicates accompanying files are available online at
www.pinnaclepublishing.com.
your code base. Continues on page 3
AD:
AGE
LL P O
FU N X
Q

2 Oracle Professional May 2005 www.pinnaclepublishing.com


Managing Code... and more.
• USER_PROCEDURES—New to Oracle9i, this view
Continued from page 1 shows you information about stored programs,
Data dictionary views for PL/SQL programmers such as the AUTHID setting, whether or not the
The Oracle data dictionary is a jungle—lushly full of program was defined as DETERMINISTIC, and so on.
incredible information, but often with less than clear • USER_SOURCE—The text source code for all objects
pathways to your destination. There are hundreds of you own (in Oracle9i and above, this includes
views built on hundreds of tables, many complex database triggers and Java source). This is a very
interrelationships, special codes, and, all too often, non- handy view, since you can run all sorts of analysis
optimized view definitions. Subsets of this multitude of the source code against it using SQL and, in
are particularly handy to PL/SQL developers; we’ll particular, Oracle Text.
take a closer look at them in a moment. First, it’s • USER_TRIGGERS and USER_TRIG_COLUMNS—
important to know that there are three types or levels The database triggers you own, and any columns
of data dictionary views: identified with the triggers. You can write programs
• USER_* views that show information about against this view to enable or disable triggers for a
the database objects owned by the currently particular table.
connected schema. • USER_ARGUMENTS—The arguments (parameters)
• ALL_* views that show information about all of the in all the procedures and functions in your schema.
database objects to which the currently connected
schema has access (either because it owns them or You can view the structures of each of these views
because it has been granted access to them). Generally either with a DESCRIBE command in SQL*Plus or by
they show the same columns as the corresponding referring to the appropriate Oracle documentation. The
USER view, with the addition of an OWNER column. following sections provide some examples of the ways
• DBA_* views that show information about all the you can use these views.
objects in the database. Generally the same columns
as the corresponding ALL view. Display information about stored objects
The USER_OBJECTS view contains the following key
We’ll work with the USER views in this article; you information about an object:
can easily modify any scripts and techniques to work • OBJECT_NAME—Name of the object.
with the ALL views by adding an OWNER column to • OBJECT_TYPE—Type of the object.
your logic. These are some of the views that a PL/SQL • STATUS—Status of the object (VALID or INVALID).
developer is most likely to find useful: • LAST_DDL_TIME—The timestamp indicating the last
• USER_DEPENDENCIES—The dependencies to and time that this object was changed.
from objects you own. This view is mostly used by
Oracle to mark objects invalid when necessary, and The following SQL*Plus script displays the status of
also by IDEs to display the dependency information PL/SQL code objects:
in their object browsers.
• USER_ERRORS—The current set of errors for all /* File on web: psobj.sql */
SET PAGESIZE 66
stored objects you own. This view is accessed by the COLUMN object_type FORMAT A20
COLUMN object_name FORMAT A30
SHOW ERRORS SQL*Plus command. You can, COLUMN status FORMAT A10
however, write your own queries against it as well. BREAK ON object_type SKIP 1
SPOOL psobj.lis
• USER_OBJECTS—The objects you own. You can, for SELECT object_type, object_name, status
instance, use this view to see if an object is marked FROM user_objects
WHERE object_type IN (
INVALID, find all the packages that have “EMP” in 'PACKAGE', 'PACKAGE BODY', 'FUNCTION',
'PROCEDURE', 'TYPE', 'TYPE BODY', 'TRIGGER')
them, and so on. ORDER BY object_type, status, object_name
• USER_OBJECT_SIZE—The size of the objects you /
SPOOL OFF
own. Actually, this view will show you the source,
parsed, and compile sizes for your code. Use it to
The output from this script file contained the
identify the large programs in your environment,
following list:
good candidates for pinning into the SGA.
• USER_PLSQL_OBJECT_SETTINGS—New to OBJECT_TYPE OBJECT_NAME STATUS
Oracle10g, this view gives you information about ------------ ----------------------- --------
FUNCTION DEVELOP_ANALYSIS INVALID
the characteristics of a PL/SQL object that can be NUMBER_OF_ATOMICS INVALID
modified through the ALTER-SET DDL command, PACKAGE CONFIG_PKG VALID
such as the optimization level, debug settings, EXCHDLR_PKG VALID

www.pinnaclepublishing.com Oracle Professional May 2005 3


Notice that two of my modules are marked BEGIN
SELECT NAME || '-' || line
as INVALID. , text
BULK COLLECT INTO info_aa
FROM user_source
Display and search source code WHERE UPPER (text) LIKE '%' || UPPER (str) || '%'
AND NAME != 'VALSTD'
You should always maintain the source code of your AND NAME != 'ERRNUMS';
programs in text files (or via a development tool
disp_header ('Checking for presence of "' || str || '"');
specifically designed to store and manage PL/SQL
code outside of the database). When you store these FOR indx IN info_aa.FIRST .. info_aa.LAST
LOOP
programs in the database, however, you can take pl (info_aa (indx).NAME, info_aa (indx).text);
advantage of SQL to analyze your source code across all END LOOP;
END progwith;
modules, which may not be a straightforward task with
your text editor. Once this package is compiled into my schema,
The USER_SOURCE view contains all of the source I can check for usages of -20,NNN numbers with
code for objects owned by the current user. The structure this command:
of USER_SOURCE is as follows:
SQL> EXEC valstd.progwith ('-20')
Name Null? Type ==================
------------------------------ -------- ---- VALIDATE STANDARDS
NAME NOT NULL VARCHAR2(30) ==================
TYPE VARCHAR2(12) Checking for presence of "-20"
LINE NOT NULL NUMBER
TEXT VARCHAR2(2000) CHECK_BALANCE - RAISE_APPLICATION_ERROR (-20306, 'Balance
too low');
MY_SESSION - PRAGMA EXCEPTION_INIT(dblink_not_open,
where NAME is the name of the object, TYPE is the type -2081);
VSESSTAT - CREATE DATE : 1999-07-20
of the object (ranging from PL/SQL program units to Java
source to trigger source), LINE is the line number, and
Notice that the third line in my output isn’t really a
TEXT is the text of the source code.
problem; it shows up only because I couldn’t define my
USER_SOURCE is a very valuable resource for
filter narrowly enough.
developers. With the right kind of queries, you can do
This is a fairly crude analytical tool, but you could
things like:
certainly make it more sophisticated. You could also have
• Display source code for a given line number.
it generate HTML that is then posted on your intranet.
• Validate coding standards.
You could then run the valstd scripts every Sunday night
• Identify possible bugs or weaknesses in your
through a DBMS_JOB-submitted job, and each Monday
source code.
morning developers could check the intranet for feedback
on any fixes needed in their code.
Suppose, for example, that we have set as a rule that
individual developers should never hard-code one of
Use program size to determine
those application-specific error numbers between -20,999
pinning requirements
and -20,000 (such hard-codings can lead to conflicting
The USER_OBJECT_SIZE view gives you the following
usages and lots of confusion). I can’t stop a developer
information about the size of the programs stored in
from writing code like this:
the database:
RAISE_APPLICATION_ERROR (-20306, 'Balance too low');
• SOURCE_SIZE—The size of the source, in bytes.
This code must be in memory during compilation
but I can create a package that allows me to identify all (including dynamic/automatic recompilation).
the programs that have such a line in them. I call it my • PARSED_SIZE—The size of the parsed form of the
“validate standards” package; it’s very simple, and its object, in bytes. This representation must be in
main procedure looks like this: memory when any object that references this object
is being compiled.
/* Files on web: valstd.pks/valstd.pkb */ • CODE_SIZE—Code size, in bytes. This code must be
PROCEDURE progwith (str IN VARCHAR2)
IS in memory when the object is being executed.
TYPE info_rt IS RECORD (
NAME user_source.NAME%TYPE
, text user_source.text%TYPE Here’s a query that allows you to show code objects
); that are larger than a given size. You might want to run
TYPE info_aat IS TABLE OF info_rt this to identify the programs that you’ll want to pin into
INDEX BY PLS_INTEGER; the database using DBMS_SHARED_POOL, to minimize
info_aa info_aat; swapping of code in the SGA:

4 Oracle Professional May 2005 www.pinnaclepublishing.com


-- File: pssize.sql than have to write this code manually, you can
SELECT name, type, source_size, parsed_size, code_size
FROM user_object_size execute the appropriate DDL statements from within
WHERE code_size > &&1 * 1000
ORDER BY code_size DESC
a PL/SQL program.
/ • Identify triggers that execute only when certain
columns are changed, but don’t have a WHEN clause.
Obtain properties of stored code A best practice for triggers is to include a WHEN
The ALL_PLSQL_OBJECT_SETTINGS (Oracle10g and clause to make sure that the specified columns
above) provides information about the following compiler actually have changed values (rather than simply
settings of a stored PL/SQL object: writing the same value over itself).
• PLSQL_OPTIMIZE_LEVEL—Optimization level
that was used to compile the object. Here’s a program that will either enable or disable all
• PLSQL_CODE_TYPE—Compilation mode for triggers on a table. It uses native dynamic SQL, since I
the object. must execute a DDL statement from within PL/SQL.
• PLSQL_DEBUG—Indicates whether or not the
object was compiled for debugging. -- File: settrig.sp
CREATE OR REPLACE PROCEDURE settrig (
• PLSQL_WARNINGS—Compiler warning settings tab IN VARCHAR2
that were used to compile the object. , sch IN VARCHAR DEFAULT NULL
, action IN VARCHAR2
• NLS_LENGTH_SEMANTICS—NLS length semantics )
that were used to compile the object. IS
l_action VARCHAR2 (10) := UPPER (action);
l_other_action VARCHAR2 (10) := 'DISABLED';
Possible uses for this view include: BEGIN
IF l_action = 'DISABLE'
• Identify any programs that aren’t taking full THEN
advantage of the optimizing compiler (an l_other_action := 'ENABLED';
END IF;
optimization level of 1 or 0):
FOR rec IN (SELECT trigger_name
FROM user_triggers
SELECT owner, name
WHERE table_owner = UPPER (NVL (sch, USER))
FROM all_plsql_object_settings
AND table_name = tab
WHERE plsql_optimize_level IN (1,0);
AND status = l_other_action)
LOOP
• Determine if any stored programs have disabled EXECUTE IMMEDIATE 'ALTER TRIGGER '
|| rec.trigger_name
compile time warnings: || ' ' || l_action;

DBMS_OUTPUT.put_line ( 'Set status of '


SELECT owner, NAME, plsql_warnings
|| rec.trigger_name
FROM all_plsql_object_settings
|| ' to '
WHERE plsql_warnings LIKE '%DISABLE%'
|| l_action
AND owner NOT IN ('SYS', 'SYSTEM');
);
END LOOP;
The ALL_PROCEDURES view gives you lists of END settrig;
/
all functions and procedures, along with associated
properties, including whether or not a function is Here’s a query you can use to identify potentially
pipelined, parallel enabled, or aggregate. ALL_ problematic triggers lacking a WHEN clause:
PROCEDURES will also show you the AUTHID setting
for a program (DEFINER or CURRENT_USER). This can SELECT *
FROM user_triggers tr
be very helpful if you need to quickly see which programs WHERE when_clause IS NULL AND
in a package or group of packages are invoker rights or EXISTS (SELECT 'x'
FROM user_trigger_cols
definer rights. Here’s an example of such a query: WHERE trigger_owner = USER
AND trigger_name = tr.trigger_name);
SELECT AUTHID
, p.object_name program_name
, procedure_name subprogram_name Analyze argument information
FROM all_procedures p, all_objects o A very useful view for programmers is USER_
WHERE p.owner = o.owner
AND p.object_name = o.object_name ARGUMENTS. It contains information about each of
AND p.object_name LIKE the arguments of each of the stored programs in your
'<package or program name criteria>'
ORDER BY AUTHID, procedure_name; schema. It offers simultaneously a wealth of nicely parsed
information about arguments and a bewildering structure
Analyze and modify trigger state through views that’s very hard to work with.
Query the trigger-related views to do any of the Here’s a simple SQL*Plus script to dump the contents
following: of USER_ARGUMENTS for all the programs in the
• Enable or disable all triggers for a given table. Rather specified package:

www.pinnaclepublishing.com Oracle Professional May 2005 5


-- desctest.sql retval VARCHAR2 ( 32767 );
SELECT object_name, argument_name, overload BEGIN
, POSITION, SEQUENCE, data_level, data_type SELECT DECODE ( MIN ( POSITION )
FROM user_arguments , 0
WHERE package_name = UPPER ('&&1') , 'FUNCTION'
/ , 'PROCEDURE')
BULK COLLECT INTO l_overloads
FROM all_arguments
A more elaborate, PL/SQL-based program for WHERE owner = owner_in
AND package_name = package_in
displaying the contents of USER_ARGUMENTS may be AND object_name = program_in
GROUP BY overload ;
found in the show_all_arguments.sp file.
You can also write more specific queries against IF l_overloads .COUNT > 0
THEN
USER_ARGUMENTS to identify possible quality issues retval :=
with your code base. For example, Oracle recommends list_to_string (
l_overloads
that you stay away from the LONG datatype and instead , ',' , distinct_in => TRUE);
END IF;
use LOBs. In addition, fixed-length datatype CHAR can
cause logic problems; you’re much better off sticking with RETURN retval;
END program_type ;
VARCHAR2. Here’s a query that uncovers the usage of /
these types in argument definitions:
Finally, you should also know that the built-in
SELECT object_name, argument_name, overload package, DBMS_DESCRIBE, provides a PL/SQL API to
, POSITION, SEQUENCE, data_level, data_type
FROM user_arguments much of the same information as USER_ARGUMENTS.
WHERE data_type IN ('LONG','CHAR')
/
There are differences, however, in the way these two
elements handle datatypes.
You can even use ALL_ARGUMENTS to deduce
information about a package’s program units that So many views, so little time!
otherwise isn’t easily obtainable. Suppose that I want to The number of data dictionary views has exploded in
get a list of all the procedures and functions defined the past several releases of Oracle. On the one hand, this
in a package specification. You might say, “No problem! is great news, since that means there’s more and more
Just query the ALL_PROCEDURES view.” And that information accessible to us through comfortable, familiar
would be a fine answer, except that it turns out that SQL. Unfortunately, we still have to go through the
ALL_PROCEDURES doesn’t tell you whether a program discovery phase of finding what’s out there and how to
is a function or procedure (in fact, it can be both, use it. I hope this article has offered some new ideas and
depending on how the program is overloaded!). useful code for you. ▲
You might, instead, wish to turn to ALL_
ARGUMENTS. It does, indeed, contain that information, 505FEUER.ZIP at www.pinnaclepublishing.com
but it’s far less than obvious. To determine whether a
program is a function or a procedure, you must check Steven Feuerstein is considered one of the world’s leading experts on
the Oracle PL/SQL language, having written nine books on PL/SQL,
to see if there’s a row in ALL_ARGUMENTS for that
including Oracle PL/SQL Programming and Oracle PL/SQL Best Practices
package-program combination that has a POSITION of
(all from O’Reilly). Steven has been developing software since 1980
0. That’s the value Oracle uses to store the RETURN and serves as a Senior Technology Advisor to Quest Software. His
“argument” of a function. If it’s not present, then the current projects include Qnxo (www.qnxo.com), a new active
program must be a procedure. mentoring software product, and the Refuser Solidarity Network
The following function uses this logic to return a (www.refusersolidarity.net), which supports the Israeli military refuser
string that indicates the program type (if it’s overloaded movement. steven@stevenfeuerstein.com.
with both types, the function returns “FUNCTION,
PROCEDURE”). Note: The list_to_string function used in
the main body is provided in the download.
Introducing the new Pinnacle Forum!
CREATE OR REPLACE FUNCTION program_type ( Post Questions. Get Responses. Right Now.
owner_in IN VARCHAR2
, package_in IN VARCHAR2
, program_in IN VARCHAR2 Discuss articles, explore Oracle-related topics, and network
) with your peers.* It’s free and simple to join, so sign up now!
RETURN VARCHAR2
IS
c_function_pos CONSTANT PLS_INTEGER := 0 ; www.pinpub.com/forum
TYPE overload_aat IS * To maintain the same level of quality you’ve come to expect from
TABLE OF all_arguments . overload %TYPE
INDEX BY PLS_INTEGER ; Oracle Professional, we do not allow anonymous postings.

l_overloads overload_aat ;

6 Oracle Professional May 2005 www.pinnaclepublishing.com


Oracle
Professional

Gently Down the Stream, Part 4


Darryl Hurley
Oracle Streams technology provides a seamless transfer of
Listing 2. Capture restart written to the alert log.
data from one place to another, making significant use of
many Oracle features like Advanced Queuing, the ANYDATA Thu Jan 27 22:01:40 2005
data type, and Log Miner. In this series of articles, Darryl Hurley C001: time limit exceeded
Thu Jan 27 22:08:41 2005
sheds light on the inner workings of Streams and provides Streams CAPTURE C001 started with pid=20, OS id=1536
insight into its usage. In this fourth installment, he completes Thu Jan 27 22:08:42 2005
LOGMINER: Parameters summary for session# = 175
his discussion of the capture component and looks at the LOGMINER: ReqParallelism = 3, EagerThreshold = 1
LOGMINER: StopMiningThreshold = 1M, MemorySize = 10M
propagation components of Streams. LOGMINER: MaxLogLookback = 10M
Thu Jan 27 22:08:43 2005

T
Streams CAPTURE C001 started with pid=20, OS id=1480
HE first three articles in this series explained how to Thu Jan 27 22:08:45 2005
set up and run a capture process, including moving LOGMINER: Parameters summary for session# = 175
LOGMINER: ReqParallelism = 3, EagerThreshold = 1
forward through redo logs. In this one, I’ll wrap LOGMINER: StopMiningThreshold = 1M, MemorySize = 10M
up the discussion of capture processes by providing LOGMINER: MaxLogLookback = 10M
LOGMINER: session# = 175, reader process P002 started
some notes on monitoring and configuration that I’ve with pid=25 OS id=1556
found useful, including checking for errors and LOGMINER: session# = 175, builder process P003 started
with pid=26 OS id=1516
configuring memory. LOGMINER: session# = 175, preparer process P004 started
with pid=27 OS id=1576

Scheduled stops
I’ve found that letting capture processes run for
One way to manage how long a capture process runs is
one hour (3,600 seconds) at a time requires the fewest
to force regular restarts whenever a certain number of
unscheduled manual restarts (your results may vary, of
messages have been captured or a number of seconds
course). So what could necessitate an unscheduled start?
have passed. Once the specified limit is reached, the
Just a few things, which I’ll discuss next.
capture process will stop. The parameter DISABLE_
ON_LIMIT controls the behavior after the stoppage: If set
Unscheduled stops
to ‘Y’ it won’t restart, and if set to ‘N’ it will automatically
I have to admit that capture processes are surprisingly
restart. Details of the starts and stops can optionally be
stable, although they do encounter errors from time to
written to the alert log as well. Listing 1 demonstrates
time. The good news is they can usually just be restarted
setting these values.
to carry on. The really good news is the cause of the
stoppage is easily gleaned from the DBA_CAPTURE view.
Listing 1. Setting time limit and write to alert log.
SQL> SELECT status,
2 status_change_time,
SQL> BEGIN
3 error_number,
2 DBMS_CAPTURE_ADM.SET_PARAMETER('CAPTURE',
4 error_message
3 'TIME_LIMIT', 5 FROM dba_capture;
4 '3600');
5 END; STATUS STATUS_CH ERROR ERROR_MESSAGE
6 / ------- --------- ----- -------------------------------
ABORTED 27-JAN-05 1280 ORA-01280: Fatal LogMiner Error
PL/SQL procedure successfully completed.

SQL> BEGIN The most common messages are described here:


2 DBMS_CAPTURE_ADM.SET_PARAMETER('CAPTURE',
3 'WRITE_ALERT_LOG',
4 'Y'); ORA-01280: Fatal LogMiner Error
5 END;
6 / This is usually because the underlying Log Miner
PL/SQL procedure successfully completed. session has been passed invalid SCN values by a capture
process. I’m not sure if it’s an Oracle bug or not, but I’ve
Listing 2 shows an example of what’s written to the frequently encountered this error even when perfectly
alert log when a capture process is restarted. valid start or first SCN values were used. A restart of the

www.pinnaclepublishing.com Oracle Professional May 2005 7


capture process fixes this. number of messages currently spilled to disk, the total
messages ever stored in the queue, and the total messages
ORA-01323: Invalid state ever spilled to disk. The shown results point to a possible
problem, because all current messages have spilled to
This occurs when a required redo log file has been disk. There’s either not enough room in the shared pool
removed. Simply re-establish the missing log file and or downstream processes aren’t consuming messages fast
restart the capture process. Alternatively, the SCN range enough. I’ll start covering downstream processes later,
could be manually advanced to the next existing redo log, and will cover the shared pool now.
but the interim changes will be lost.

ORA-01304: subordinate process error.


Shared pool
Check alert and trace logs Two rules of thumb apply to memory allocation for
Streams:
I encountered this one a lot when capture processes • Each capture process needs at least 10MB of
restarted after reaching message count limits I had shared pool.
specified. Consult the databases alert log and any trace • Streams messages are limited to 10 percent of the
files it references for details. I’ve found that a restart of shared pool. Excess will spill to disk.
the capture process is all that’s required.
Oracle 9 offered control of the percentage allowed for
ORA-04031: unable to allocate bytes
of shared memory ("","","","")
messages via a somewhat generically named hidden
database initialization parameter: _first_spare_parameter.
Streams use the Shared Pool portion of the SGA, and Oracle 10 simplifies things by setting aside a portion of
if they run out of room this error will be raised. I cover the shared pool for Streams via the appropriately named
memory allocation later in this article. STREAMS_POOL_SIZE parameter.

SQL> SELECT name,


Monitoring messages 2 value
It’s always a good idea to keep an eye on how many 3 FROM v$parameter
4 WHERE name = 'streams_pool_size';
messages a capture process has handled and enqueued,
especially if a message limit is enabled. Both values can NAME VALUE
-------------------- ------------------
be queried from the performance view V$STREAMS_ streams_pool_size 12582912
CAPTURE as shown here:
Note that this value isn’t managed within Oracle’s
SQL> SELECT CAPTURE_NAME, Automatic Memory Management feature. It must be
2 TOTAL_MESSAGES_CAPTURED,
3 TOTAL_MESSAGES_ENQUEUED altered manually via the ALTER SYSTEM command if
4 FROM V$STREAMS_CAPTURE; required. Once this allocation is used up, capture
CAPTURE_NAME CAPTURED ENQUEUED processes will fail and/or not start, so it’s important to
------------- -------- --------
CAPTURE 8198 1
monitor this closely. A query to check it is shown in
Listing 3.
This means the capture process has interrogated 8,198
messages, of which only one satisfied its rule and was Listing 3. Querying the status of the streams pool.
queued up to swim downstream.
Another message-related area to monitor is the SQL> SELECT name,
2 bytes
number forced to disk due to lack of space in the shared 3 FROM v$sgastat
pool. This is referred to as spillage, and its status is 4 WHERE pool = 'streams pool'
5 ORDER BY name;
queried like this:
NAME BYTES
-------------------------- ----------
SQL> SELECT queue_name,
NP Prop Status 4080
2 num_msgs,
Sender info 8532
3 spill_msgs,
deqtree_kgqmctx 72
4 cnum_msgs,
free memory 12531184
5 cspill_msgs
kgqmsub 120
6 FROM v$buffered_queues;
kgqtbt_alloc_block 4144
kwqbcqini:spilledovermsgs 2096
QUEUE_NAME MSGS SPILL CNUM CSPILL
kwqbmrrcpt 6032
------------- ---- ----- ---- ------
kwqbsinfy:bmsg 4176
CAPTURE_QUEUE 47 47 77 57
kwqbsinfy:bqgc 3936
kwqbsinfy:stat 4160
msgtree_kgqmctx 72
From left to right, the query shows the queue name, name_kgqmsub 48
the number of messages currently in the queue, the ppdeqmsg[i] 1316

8 Oracle Professional May 2005 www.pinnaclepublishing.com


ppdeqmsg_kgqmmsg 752 16 attribute_name => 'THREAD#',
qtree_kwqpspse 36 17 include => TRUE);
recov_kgqbtctx 7924 18 DBMS_CAPTURE_ADM.INCLUDE_EXTRA_ATTRIBUTE(
recov_kgqmctx 536 19 capture_name => 'CAPTURE',
recov_kgqmsub 536 20 attribute_name => 'TX_NAME',
spilled:kwqbls 4232 21 include => TRUE);
substree_kgqmctx 72 22 DBMS_CAPTURE_ADM.INCLUDE_EXTRA_ATTRIBUTE(
23 capture_name => 'CAPTURE',
24 attribute_name => 'USERNAME',
I’m not even going to try and decipher what most of 25 include => TRUE);
26 END;
these values mean except for free memory, which is just
that—the amount of remaining free memory. This value
Including ROWID values isn’t useful when applying
should only fluctuate greatly when capture processes are
changes to other tables or databases, so I excluded them
started or stopped, as shown in this query using Oracle’s
with the first command. The second command initiates
Automatic Workload Repository statistics.
the recording of the serial number for the session
SQL> SELECT begin_interval_time "begin", performing the DML. The third command includes the
2 end_interval_time "end", session number (better known as the session ID or SID).
3 bytes
4 FROM dba_hist_sgastat sga, The fourth command records the database thread number
5 dba_hist_snapshot snap of the DML. The fifth includes the name of a transaction
6 WHERE pool = 'streams pool'
7 AND name = 'free memory' established using the SET TRANSACTION NAME
8 AND sga.snap_id = snap.snap_id
9 ORDER BY sga.snap_id;
command. Last but not least, the sixth command includes
the name of the Oracle user that executed the DML.
BEGIN END BYTES
--------------- --------------- ---------- Downstream processes consuming captured LCRs can
08.09.22.000 PM 08.21.14.158 PM 12520292 parse all of these extra attributes, as I’ll show you in a
08.21.14.158 PM 08.37.38.854 PM 12520292
08.37.38.854 PM 08.51.23.419 PM 606364 later article.
08.51.23.419 PM 09.00.16.536 PM 602184 Further isolation is available via tags that can be
09.00.16.536 PM 09.43.27.742 PM 12509708
09.43.27.742 PM 09.51.12.871 PM 651560 applied to subsequent DML as one might apply a tag
09.51.12.871 PM 10.01.01.537 PM 643132 to a fish. Listing 5 shows the syntax to set and retrieve a
tag value.
Obviously, the capture process was running between
8:37 and 9:00 and again between 9:43 and 10:01 because
that’s when the free memory in the streams pool was at its Listing 5. Tagging LCRs.
lowest points.
SQL> EXEC DBMS_STREAMS.SET_TAG(tag =>
My experience has been that 10MB is more than UTL_RAW.CAST_TO_RAW('SPAWN COUNT'));
enough per capture process as long as the downstream
PL/SQL procedure successfully completed.
processes are able to consume messages fast enough to
prevent things from backing up. SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 raw_tag RAW(2000);
3 BEGIN
Extra information 4 raw_tag := DBMS_STREAMS.GET_TAG();
As I explained in a prior article, the Logical Change 5 DBMS_OUTPUT.PUT_LINE('Tag Value = '
6 || UTL_RAW.CAST_TO_VARCHAR2(raw_tag));
Records (LCRs) extracted by capture processes contain 7 END;
a lot of information about a DML operation. But 8 /
Tag Value = SPAWN COUNT
sometimes it’s important to isolate things even for explicit
downstream processing. To this end, several values can be Tags take effect immediately, but only remain for
attached to subsequent LCRs as shown in Listing 4. the rest of the Oracle session or until they’re unset.
Downstream processes can evaluate tags to make
Listing 4. Extra attributes. decisions when reapplying DML. The downside of tags
is that they make evaluating rules for LCRs a little
SQL> BEGIN complicated, as I’ll discuss in a future article.
2 DBMS_CAPTURE_ADM.INCLUDE_EXTRA_ATTRIBUTE(
3 capture_name => 'CAPTURE',
All right already, that’s enough about capture
4 attribute_name => 'ROW_ID', processes. The next sections start looking at the first
5 include => FALSE);
6 DBMS_CAPTURE_ADM.INCLUDE_EXTRA_ATTRIBUTE( downstream process—the aptly named propagate process
7 capture_name => 'CAPTURE', that moves messages from capture queues to apply
8 attribute_name => 'SERIAL#',
9 include => TRUE); queues for subsequent application.
10 DBMS_CAPTURE_ADM.INCLUDE_EXTRA_ATTRIBUTE(
11 capture_name => 'CAPTURE',
12 attribute_name => 'SESSION#', Propagation
13 include => TRUE); In a Streams environment, propagation is defined as
14 DBMS_CAPTURE_ADM.INCLUDE_EXTRA_ATTRIBUTE(
15 capture_name => 'CAPTURE', moving Logical Change Records (LCRs) from one queue

www.pinnaclepublishing.com Oracle Professional May 2005 9


to another, or more specifically from a capture queue to an The three control values are:
apply queue. The move is necessary for two reasons: One • next_time—A function used to calculate the next
is to get records out of the capture queue as quickly as time the propagation should start up. Usually sysdate
possible, freeing up valuable space in the database shared plus an interval such as ‘SYSADTE + 1’ is used for
pool; and the second is because apply queues are daily runs.
persistent, so LCRs can be processed at whatever pace is • duration—The number of seconds a propagation
desired. In the following sections I’ll create a propagation process will run before shutting down and waiting
process to quickly move my fish log entries to an apply for its next time to arrive to fire up again. This is also
queue where they can eventually be applied. referred to as the propagation window.
• latency—The maximum amount of time an LCR will
Fishy propagation be allowed to sit unmoved in the capture queue. This
Because propagation processes are relatively simple, they is synonymous to the amount of time a process would
can be controlled from one or two PL/SQL packages. The sleep if no entries were found to process. A value of
first one, DBMS_PROPAGATION_ADM, is what I’ll use zero means entries will be propagated immediately.
to get things started. Note the latency is only in effect if the propagation is
actually working within a window.
BEGIN
DBMS_PROPAGATION_ADM.CREATE_PROPAGATION(
propagation_name => 'PROPAGATE', Because my main objective is to move records as
source_queue => 'STREAMS.CAPTURE_QUEUE',
destination_queue => 'STREAMS.APPLY_QUEUE');
quickly as possible, I’m setting the schedule to be
END; continuous using a next time of SYSDATE (meaning the
next time is always “now”) and a latency of 0 seconds,
This creates a propagation process named meaning LCRs won’t wait at all in the capture queue.
PROPAGATE to move records from the CAPTURE_
QUEUE that I covered previously to the APPLY_QUEUE, BEGIN
DBMS_AQADM.ALTER_PROPAGATION_SCHEDULE(
which I’ll explain later. queue_name => 'STREAMS.CAPTURE_QUEUE',
next_time => 'SYSDATE',
latency => 0);
Propagation isolation END;
By default this propagation will move every record in the
capture queue over to the apply queue. But in the interest Notice the use of the DBMS_AQADM package from
of fast processing I’ll isolate it to just my records using a Oracle’s Advanced Queuing (AQ) implementation.
rule. The cool thing is that the rule used on the capture Propagation also utilizes the AQ timing utilities to
process can be reused, as shown here. determine when to run, so the database’s AQ_TM_
PROCESSES parameter must be set to at least 1.
SQL> SELECT rule_set_owner, Once AQ decides it’s time to run propagation, it
2 rule_set_name
3 FROM dba_capture uses an Oracle job queue to perform the run. Thus, the
4 WHERE capture_name = 'CAPTURE';
database’s JOB_QUEUE_PROCESSES parameter must be
RULE_SET_OWNER RULE_SET_NAME set to accommodate it.
------------------------------ -------------
STREAMS RULESET$_78
Scheduling
SQL> BEGIN
2 DBMS_PROPAGATION_ADM.ALTER_PROPAGATION( Details of the propagation schedule can be seen using
3 propagation_name => 'PROPAGATE', this query from the DBA_QUEUE_SCHEDULES view
4 rule_set_name => 'STREAMS.RULESET$_78');
5 END; in Oracle10g:
6 /

PL/SQL procedure successfully completed. SQL> SELECT start_date,


2 start_time,
3 propagation_window,
Always propagating 4 next_time
5 FROM dba_queue_schedules;
Unlike capture processes, propagations don’t need to be
stopped and started. They’re always running. Well, not START_DAT START_TI PROPAGATION_WINDOW NEXT_TIME
--------- -------- ------------------ ---------
always actually running. They work in windows 01-MAR-05 21:05:41 SYSDATE
controlled with start/next times and durations. When a
queue is created, it starts up and will run for its allotted Because my queue is always running, the propagation
duration. When it finishes, it will stop until its next window shows as null.
allotted start time. For example, a propagation could be
scheduled to start every hour and run for 10 minutes, or Status
start at 10:00 a.m. every day and run for one hour. To view statistics on the sending side of propagation, you

10 Oracle Professional May 2005 www.pinnaclepublishing.com


can use this query: 5 FROM dba_queue_schedules,
6 dba_propagation
7 WHERE destination_dblink = destination
SQL> SELECT high_water_mark, 8 AND schema = source_queue_owner
2 acknowledgement, 9 AND qname = source_queue_name;
3 schedule_status,
4 total_msgs, PROPAGATION_NAME TIME NUMBER FAILURES
5 total_bytes, ---------------- ---- ------ --------
6 elapsed_propagation_time PROPAGATE 60 22 0
7 FROM v$propagation_sender;

HWM ACK SCHEDULE_STATUS MSG BYTE ELAPSED Error conditions


---- ---- ---------------- ---- ----- -------
17 17 SCHEDULE ENABLED 17 4029 1591 If the propagation fails, the Oracle error number and
message can be found in the DBA_PROPAGATE view
This means my propagation process has handled as using this query:
much as 17 messages at once, comprised of 4,029 bytes of
content, and has run for 1,591 seconds. SELECT last_error_date,
last_error_time,
On the other end of things, the receiver’s status is last_error_msg
viewed with this query: FROM dba_queue_schedules;

SQL> SELECT high_water_mark, The most common cause of failure for propagations
2 acknowledgement,
3 elapsed_rule_time,
is the destination apply queue being unreachable. For
4 elapsed_enqueue_time example, if the destination was in another Oracle database
5 FROM v$propagation_receiver
6 / and the Listener was down, it would be impossible to
connect in order to propagate LCRs.
HWM ACK RULE_TIME ENQUEUE_TIME
---- ---- ---------- ------------ That’s really all there is to cover with regards to
17 17 0 0 propagation processes. They’re relatively simple to set
up and monitor compared to capture processes, as I
The key thing to note here is that the same number of discussed previously, and apply processes, which I’ll
messages (17) has been received. Also of note is the time start covering in the next installment of this series. See
the receiver process has spent evaluating the rule and to you then. ▲
enqueue the LCR in the apply queue. So far it’s been so
fast that no time has been recorded. Darryl Hurley has been working with Oracle technology for 15 years with
An overview of the propagation is shown in this a significant focus on database administration and PL/SQL development.
query showing the time spent propagating, the number His days are spent as the Senior Database Developer for MDSI Mobile
of messages propagated, and the number of failures to Data Solutions Inc. (www.mdsi-advantex.com), and his spare time is spent
propagate (thankfully, zero so far). writing articles and teaching under the moniker of ImpleStrat Solutions
(www.implestrat.com). He has written several articles for the Oracle
SQL> SELECT propagation_name, Development Tools User Group (www.odtug.com) and contributed to
2 total_time,
3 total_number, several Oracle books from O’Reilly (www.ora.com). dhurley@mdsi.ca or
4 failures darryl.hurley@implestrat.com.

Pinnacle Publishing Presents: Steven Feuerstein’s Oracle PL/SQL Spotlight Series


The online training event Oracle DBAs and developers have been waiting for...

Participate in three dynamic Webinars, offering in-depth With Pinnacle’s Webinars, you can receive quality, cost-
training with world-renowned Oracle PL/SQL author Steven effective online training at your fingertips. Why spend training
Feuerstein, on key features of the PL/SQL language. dollars on travel, when you can learn from the experts from
your desk or conference room? Our Webinars make it
Webinar #1: “Spotlight on Collections” possible to offer expert training to large numbers of developers
June 8, 2005: 8:00 am-10:00 am (CT), 2:00 pm-4:00 pm (CT) in your organization. You no longer have to send a single
Webinar #2: “Spotlight on Native Dynamic SQL” “representative,” who must then return and attempt to pass on
June 23, 2005: 8:00 am-10:00 am (CT), 2:00 pm-4:00 pm (CT) what he or she learned. Everyone can attend!

Webinar #3: “Spotlight on Exception Handling” Visit www.pinpub.com/op for complete event details and
July 13, 2005: 8:00 am-10:00 am (CT), 2:00 pm-4:00 pm (CT) online registration.

www.pinnaclepublishing.com Oracle Professional May 2005 11


Oracle
Professional

Getting DDL with


DBMS_METADATA
Al Hetzel
Maybe you’re migrating your database to a new platform. quickly and easily display the DDL directly from the data
Maybe you want to create a copy of one database to use as a dictionary. You can use this powerful package to display
test database. Maybe you just lost the code. Whatever the individual objects or an entire schema. Let’s take a look at
reason, the problem is the same: You need the DDL for one how it works.
of the objects in your database. Whether the object is a table,
a view, a db_link, or one of several dozen other objects, you Using GET_DDL
can get the DDL easily using the DBMS_METADATA package, The GET_DDL function creates the actual DDL. This
which has been available since Oracle9i. In this article, Al function can take up to six parameters—object_type,
Hetzel explains this package and shows some tips on using object_name, schema_name, version, model, and
it effectively. transform (see Listing 1).

P
RIOR to Oracle9i, getting the DDL for a database
Listing 1. The GET_DDL function
object was something of a challenge. You could
DESC a table to get the column information. dbms_metadata.get_ddl(
However, you would still need the indexes, foreign <object_type>,
<object_name>,
keys, and constraints. Getting this information could be <schema_name>,
extremely time-consuming, since there were only three <version>,
<model>,
main ways to do it: <transform> )
• Use the export utility (EXP). By setting ROWS=NO,
you could get the DDL by exporting the tables. The object_type refers to the type of database object
However, the results were poorly formatted. You that’s being reverse engineered. This type will be one of
would have to pull out the DDL and then reformat it the Oracle standard objects. A complete list of the objects
before being able to use it. that can be retrieved through the GET_DDL function is
• Create a dictionary script. All of the object definitions shown in the “Identifying potential objects” section of this
are contained in one or more SYSTEM tables. You article. The object_type is a required parameter.
could create a script to search through those tables The object_name refers to the actual name of the
and painstakingly reconstruct the object. Of course, object. Since each name must be unique within a schema,
you had to know which SYSTEM tables to use and the object_name will identify the specific object. This
how to put the data together. Also, you could only get parameter is also required.
those objects for which you had created a script. The schema_name refers to the schema that holds the
• Use a third-party tool. If you didn’t want to deal with object. Using this parameter, object_type, and object_
the problems with the first two solutions, you could name, any single object on the database can be identified.
buy a third-party tool. Some of these tools were This parameter is optional. If it’s not included, then the
extremely useful even though you did have to buy current schema is used as the default.
and configure them for use with your database. The version refers to the specific database version
Unfortunately, not all of the tools provided of the DDL. This parameter is used for backwards
everything you needed. Some might give you the compatibility since it will only extract the DDL that’s
constraints but not the storage parameters. Some compatible with the specified version. The three legal
might give you the primary and foreign keys but values for this parameter are COMPATIBLE, which
nothing else. corresponds to the database compatibility level (must be
set to 9.0.1 or higher), LATEST, which corresponds to the
With Oracle9i and 10g, we now have a new built-in current database version, or a specific database version
package called DBMS_METADATA. This package will (for example, 9.0.1). This parameter is optional. If it’s not

12 Oracle Professional May 2005 www.pinnaclepublishing.com


included, it will default to COMPATIBLE.
Table 1. Objects that can be used with DBMS_METADATA.
The model refers to any of the supported views. This
parameter will eventually allow the DDL extracted to be ASSOCIATION LIBRARY SEQUENCE
formatted into any of the views allowed by the API. AUDIT MATERIALIZED_VIEW SYNONYM
However, the current version of the package will only AUDIT_OBJ MATERIALIZED_VIEW_LOG SYSTEM_GRANT
support the ORACLE model. This parameter is optional. CLUSTER OBJECT_GRANT TABLE
COMMENT OPERATOR TABLESPACE
If it’s not included, it will default to ORACLE. CONSTRAINT OUTLINE TABLESPACE_QUOTA
The previous five parameters determine which object CONTEXT PACKAGE TRIGGER
will have its DDL displayed. Transform determines how DB_LINK PACKAGE_SPEC TRUSTED_DB_LINK
the resulting DDL will look. Numerous settings can be DEFAULT_ROLE PACKAGE_BODY TYPE
DIMENSION PROCEDURE TYPE_SPEC
used to display the results in whatever manner is desired, DIRECTORY PROFILE TYPE_BODY
which I’ll discuss later. This parameter is also optional. FUNCTION PROXY USER
In addition, it can be set using another part of the INDEX REF_CONSTRAINT VIEW
DBMS_METADATA package, the SET_TRANSFORM_ INDEXTYPE ROLE XMLSCHEMA
JAVA_SOURCE ROLLBACK_SEGMENT
PARAM procedure.
Since GET_DDL is a function, you call it as part of a
SQL or PL/SQL statement. For the examples that I’ll use
here, it will be part of a SQL statement that uses the dual displays in SQL*Plus. In particular, only a certain number
table. The statement that will be used for all future of characters of a CLOB will be displayed in SQL*Plus by
examples will be the following: default (see Figure 1).
The results aren’t very useful. After all, if you’re using
SELECT dbms_metadata.get_ddl('TABLE','CUSTOMERS','OE') this package, you generally want the complete DDL and
FROM dual;
not just the first few characters. We can fix this by setting
In this SQL statement, we want to get the DDL for the a few of the SQL*Plus environment variables.
customers table on the OE schema. Although I’ll use this First, we’ll turn the heading and echo off. We just
example throughout the rest of this article, tables aren’t want the DDL. We don’t need the headings to be
the only thing that we can reverse engineer. displayed, particularly since they would have displayed
throughout the results. We don’t need the command to
Identifying potential objects show up either.
The GET_DDL function on the DBMS_METADATA Second, we need to change the number of characters
package will reverse engineer more than three dozen of the CLOB that will display on the screen. The
different object types. These types are shown in Table 1. environment variable that determines this number is
As you can see from Table 1, you can get the DDL for called long. We can set long to a sufficiently large number
the standard database objects such as tables, sequences, to display the entire DDL. For our example, we’ll use
and views. You can also get the DDL for database code 10,000 as our large number (see Figure 2).
such as functions, packages, and triggers. You can even These results are much more complete. Perhaps
get the DDL for the more unusual database objects such as they have too much information. Do we really want to
dimensions, java_sources, and xmlschemas. use the same storage details as the current table? Do we
really want to use the same tablespace name? We might,
Setting variables but we might not. If we don’t need all of the information
You should remember one thing when using the displayed by default, we can limit it by using the
GET_DDL function: It returns the DDL in a CLOB. A SET_TRANSFORM_PARAM procedure that’s also in the
CLOB is subject to a number of constraints as to how it DBMS_METADATA package.

Figure 1. Default
CLOB returned.

www.pinnaclepublishing.com Oracle Professional May 2005 13


Transforming the results procedure. All of them are covered in Table 2. This field is
The SET_TRANSFORM_PARAM procedure changes also required.
the way the GET_DDL function returns the DDL. The The boolean_value is either true or false, depending
procedure takes three parameters—
transform_handle, parameter_name,
and boolean_value (see Listing 2).
Since it’s a procedure, you execute
it directly.

Listing 2. The SET_TRANSFORM_


PARAM procedure.

dbms_metadata.set_transform_param(
<transform_handle>,
<parameter_name>,
<boolean_value> )

The transform_handle is a
numeric value that represents the
specific session. You don’t need to
know this number. Instead, you can
use the SESSION_TRANSFORM
variable from the DBMS_
METADATA package. This number
is required to use the procedure.
The parameter_name is the
specific parameter that you want to
change. There are 20 different
parameters than can be set with this Figure 2. CLOB with some different settings.

Table 2. Changeable parameters.

Parameters for all objects (value in parentheses represents default)


• DEFAULT (N/A). If TRUE, all parameters are reset to the default values.
• INHERIT (FALSE). If TRUE, all parameters are inherited from system-level.
• PRETTY (TRUE). If TRUE, DDL output is formatted with indentations and line feeds.
• SQLTERMINATOR (FALSE). If TRUE, a SQL terminator (; or /) is appended to the DDL statement.
Parameters for TABLE objects
• CONSTRAINTS (TRUE). If TRUE, DDL generates non-referential table constraints.
• CONSTRAINTS_AS_ALTER (FALSE). If TRUE, table constraints are generated as separate ALTER TABLE and CREATE INDEX statements. If FALSE, table
constraints are generated as part of the CREATE TABLE statement.
• OID (FALSE). If TRUE, DDL generates the OID clause for object tables.
• REF_CONSTRAINTS (TRUE). If TRUE, DDL generates referential constraints.
• SEGMENT_ATTRIBUTES (TRUE). If TRUE, DDL generates segment attributes (physical attributes, storage attributes, tablespace, logging).
• STORAGE (TRUE). If TRUE, DDL generates the storage clause. Automatically FALSE if SEGMENT_ATTRIBUTES is FALSE.
• TABLESPACE (TRUE). If TRUE, DDL generates tablespace information. Automatically FALSE if SEGMENT_ATTRIBUTES is FALSE.
• SIZE_BYTE_KEYWORD (FALSE). If TRUE, DDL generates the BYTE keyword as part of the size specification of CHAR and VARCHAR2 columns that
use bytes.
Parameters for INDEX objects
• SEGMENT_ATTRIBUTES (TRUE). If TRUE, DDL generates segment attributes (physical attributes, storage attributes, tablespace, logging).
• STORAGE (TRUE). If TRUE, DDL generates storage clause. Automatically FALSE if SEGMENT_ATTRIBUTES is FALSE.
• TABLESPACE (TRUE). If TRUE, DDL generates tablespace information. Automatically FALSE if SEGMENT_ATTRIBUTES is FALSE.
Parameters for TYPE objects
• BODY (TRUE). If TRUE, DDL generates the type body.
• SPECIFICATION (TRUE). If TRUE, DDL generates the type specification.
Parameters for PACKAGE objects
• BODY (TRUE). If TRUE, DDL generates the package body.
• SPECIFICATION (TRUE). If TRUE, DDL generates the package specification.
Parameters for VIEW objects
• FORCE (TRUE). If TRUE, DDL uses the FORCE keyword.

14 Oracle Professional May 2005 www.pinnaclepublishing.com


on whether you want the specific parameter or not. This
Listing 3. Example parameters transformed.
field is an optional field. If you omit the field, it will
default to true. exec dbms_metadata.set_transform_param(
dbms.session_transfer, 'DEFAULT' );
Before making any changes to our example, let’s exec dbms_metadata.set_transform_param(
decide what parameter changes we want to make. Since dbms.session_transfer, 'SQLTERMINATOR', true );
exec dbms_metadata.set_transform_param(
our example is a table, only those parameters that affect dbms.session_transfer, 'CONSTRAINTS_AS_ALTER', true );
exec dbms_metadata.set_transform_param(
table objects or all objects will be of any use. We could dbms.session_transfer, 'SEGMENT_ATTRIBUTES', false );
change the others, but it wouldn’t do much for this
example (see Listing 3). First, we should reset the parameters. This is more of
a precaution than anything else. By
using the ‘DEFAULT’ parameter, we
change all parameters back to their
default values. If you’ve just opened
a SQL*Plus session, you wouldn’t
need to do this since the parameters
are still at their defaults. However,
if you’ve been working with the
package, resetting the parameters
wouldn’t hurt and might stop some
unexpected results.
Second, we’ll turn on the
SQLTERMINATOR parameter. This
parameter will put a semicolon (;) on
the end of each DDL statement. We
need this semicolon before we can
use the statement. We might as well
put it on as we create the DDL.
Third, we’ll turn on the
CONSTRAINTS_AS_ALTER
parameter. With this parameter on,
all constraints will be put into a
Figure 3. Transformed CLOB. separate DDL as the CREATE TABLE.

Don’t miss another issue! Subscribe now and save!


Subscribe to Oracle Professional today and receive a special one-year introductory rate:
Just $179* for 12 issues (that’s $20 off the regular rate)

NAME ❑ Check enclosed (payable to Pinnacle Publishing)


❑ Purchase order (in U.S. and Canada only); mail or fax copy
COMPANY
❑ Bill me later
❑ Credit card: __ VISA __MasterCard __American Express
ADDRESS
CARD NUMBER EXP. DATE

CITY STATE/PROVINCE ZIP/POSTAL CODE


SIGNATURE (REQUIRED FOR CARD ORDERS)

COUNTRY IF OTHER THAN U.S.


Detach and return to:
Pinnacle Publishing ▲ 316 N. Michigan Ave. ▲ Chicago, IL 60601
E-MAIL Or fax to 312-960-4106

* Outside the U.S. add $30. Orders payable in


INS5
PHONE (IN CASE WE HAVE A QUESTION ABOUT YOUR ORDER) U.S. funds drawn on a U.S. or Canadian bank.

Pinnacle, A Division of Lawrence Ragan Communications, Inc. ▲ 800-493-4867 x.4209 or 312-960-4100 ▲ Fax 312-960-4106

www.pinnaclepublishing.com Oracle Professional May 2005 15


The constraints that are separated include check First, the DDL includes the owner of the table, OE. If
constraints, primary keys, and foreign keys but exclude you wanted to re-create this table with a different owner,
not null constraints. If we were going to reverse you’d need to change the DDL.
engineer a number of interrelated tables, we wouldn’t Second, one of the constraints is a foreign key. Since
need to know the exact order to re-create them. Instead, this constraint references a table other than the one that
we could create all of the tables and then add the will be created, you need to make sure that table exists
constraints afterwards. before running that portion of the code.
Fourth, we’ll turn off the SEGMENT_ATTRIBUTES
parameter. With this parameter turned off, the storage and And more
tablespace clauses won’t be displayed. We’re doing this in Although this article focused exclusively on creating DDL
the example mainly for readability. using the DBMS_METADATA, you can do much more
The transformations can be applied in any order with with this package. For instance, you can get XML rather
one exception: The DEFAULT parameter must be used than DDL. And, you can convert that XML to a table and
first since it resets all of the others. Once we apply these vice versa. This package does more than just free you
transformations, we can generate the CLOB again (see from third-party tools, export functions, and database
Figure 3). scripts. It opens up a completely new method of moving
This time, our results are a lot more usable. First, we metadata around. ▲
get the DDL to create the table. Immediately after that, we
get the DDL to create all of the constraints for the table. Al Hetzel has worked as a freelance database/Web developer for more
For the most part, this DDL can be used to re-create the than two years and has worked with Oracle for more than 15 years. He’s
full table anywhere. There are only two things that you specialized in integrating Oracle with ASP and has written dozens of
need to be careful of. articles on the topic. al@activeniche.com.

May 2005 Downloads


• 505FEUER.ZIP—Source code to accompany Steven Feuerstein’s article, “Managing Code in the Database.”

For access to current and archive content and source code, log in at www.pinnaclepublishing.com.

Editor: Garry Chan (gchan@procaseconsulting.com) Oracle Professional (ISSN 1525-1756)


Contributing Editor: Bryan Boulton is published monthly (12 times per year) by:
CEO & Publisher: Mark Ragan
Pinnacle Publishing
Group Publisher: Michael King A Division of Lawrence Ragan Communications, Inc.
Executive Editor: Farion Grove 316 N. Michigan Ave., Suite 300
Chicago, IL 60601
Questions?
POSTMASTER: Send address changes to Lawrence Ragan Communications, Inc., 316
N. Michigan Ave., Suite 300, Chicago, IL 60601.
Customer Service:
Phone: 800-920-4804 or 312-960-4100 Copyright © 2005 by Lawrence Ragan Communications, Inc. All rights reserved. No part
Fax: 312-960-4106 of this periodical may be used or reproduced in any fashion whatsoever (except in the
case of brief quotations embodied in critical articles and reviews) without the prior
Email: PinPub@Ragan.com
written consent of Lawrence Ragan Communications, Inc. Printed in the United States
of America.
Advertising: RogerS@Ragan.com
Oracle, Oracle 8i, Oracle 9i, PL/SQL, and SQL*Plus are trademarks or registered trademarks of
Editorial: FarionG@Ragan.com 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): $199; two years (24 issues): $348 implied, respecting the contents of this publication, including but not limited to implied
Other:* One year: $229; two years: $408 warranties for the publication, performance, quality, merchantability, or fitness for any particular
purpose. Lawrence Ragan Communications, Inc., shall not be liable to the purchaser or any
Single issue rate: other person or entity with respect to any liability, loss, or damage caused or alleged to be
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.

16 Oracle Professional May 2005 www.pinnaclepublishing.com

You might also like