Professional Documents
Culture Documents
OracleProf - 2004 - 10
OracleProf - 2004 - 10
Resolving NAME_
RESOLVE Issues
Steven Feuerstein
In this article, Steven Feuerstein explores the weaknesses in one of the DBMS_
UTILITY programs—NAME_RESOLVE—and shows you how he came up with
an alternative.
I
’VE long held strongly mixed feelings about the DBMS_UTILITY package. I
refer to it in my classes as the “remainders bin” of built-in packages: As far
as I can tell, if someone inside Oracle builds a program that’s useful to them
(and maybe one or two others) but doesn’t clearly belong anywhere else, it October 2004
gets tossed into DBMS_UTILITY.
Volume 11, Number 10
The quality of code inside this package seems a bit uneven. Of the 31
programs defined in DBMS_UTILITY in Oracle9i Release 2 (a number I 1 Resolving NAME_
arrived at by executing the following query: SELECT COUNT(*) FROM RESOLVE Issues
ALL_PROCEDURES WHERE OBJECT_NAME = ‘DBMS_UTILITY’), several Steven Feuerstein
have very dubious track records:
9 Using Autonomous
• RECOMPILE_SCHEMA—It’s supposed to recompile all invalid objects, Transactions
but it seems to ignore the dependency tree of those objects, so it often Moru Nuhamovici
invalidates many objects in the course of recompiling the currently
12 Techniques in Oracle Reports
invalid objects.
Error Message Handling
• TABLE_TO_COMMA and COMMA_TO_TABLE—These could be fairly Bulusu Lakshman
useful delimited string parsing utilities... except they only work with
comma-delimited strings and, worse, the elements in the string must 16 October 2004 Downloads
be valid PL/SQL identifiers. Go figure.
• NAME_RESOLVE—Another program with high potential, NAME_
RESOLVE is supposed to take the name of an object—say, “SALES_
PKG.CALC_TOTALS”—and return all of the individual component Indicates accompanying files are available online at
www.pinnaclepublishing.com.
elements of the specified object (schema, object name, sub-object name,
object type, database link). Unfortunately, it only PROCEDURE DBMS_UTILITY.NAME_RESOLVE
Argument Name Type In/Out
seems to work with stored program object names, --------------------- --------- ------
and it doesn’t resolve objects accessible through NAME VARCHAR2 IN
CONTEXT NUMBER IN
synonyms properly in all cases. SCHEMA VARCHAR2 OUT
PART1 VARCHAR2 OUT
So what’s a developer to do? We dutifully inform PART2 VARCHAR2 OUT
DBLINK VARCHAR2 OUT
Oracle of the problems we find... and then build our own PART1_TYPE NUMBER OUT
substitutes. For example, Solomon Yakobson wrote a OBJECT_NUMBER NUMBER OUT
program to recompile all objects that’s been available on
the Quest Pipeline for years; it does things right, using In other words, pass in the object name as a single
CONNECT BY START WITH to make sure that objects are string, as well as a context value, and receive back all the
recompiled in the right order. resolved elements of the name (plus the object number
As for string parsing, well, there must be hundreds, or handle).
maybe thousands of such programs circulating. I wrote Looking at this list, some questions immediately arise:
one in 2002 called str2list, which parses a delimited string • What the heck is that CONTEXT?
(you specify the delimiter) and then deposits the elements • What are the PART1_TYPE values?
into your collection via native dynamic SQL. That was fun • Why isn’t there a PART2 type?
and I’m including it in the Download for this article. • How are PART1 and PART2 filled for various types
And most lately, in my work on Qnxo (active of objects?
mentoring software available at www.qnxo.com), I’ve
come to rely heavily on DBMS_UTILITY.NAME_ To answer these questions, of course, we’ll
RESOLVE—which has prompted me, with help from my journey forth into the world of Oracle documentation.
colleague, Leonid Khukhlovich, to come up with a Table 1 displays what the Supplied PL/SQL Packages
program that enhances and completes NAME_RESOLVE, and Types Reference has to say about NAME_RESOLVE
so that it works for almost all object types and isn’t parameters.
befuddled by synonyms. That helps a little bit. For example, Oracle implies
here (and in other places like Metalink states it more
The Oracle story on explicitly) that NAME_RESOLVE is only to be used
DBMS_UTILITY.NAME_RESOLVE with stored programs. It does not, however, tell us
Before we go exploring in the nooks and crannies of anything useful regarding CONTEXT. What are we
NAME_RESOLVE, let’s first see what Oracle has to say supposed to pass for that parameter? I think the time
about the program. Its parameter list (from a DESCRIBE has come to build some scripts that actually exercise
DBMS_UTILITY command in SQL*Plus) is: NAME_RESOLVE, and unveil its secrets.
Parameter Description
name This can be of the form [[a.]b.]c[@d], where a, b, c are SQL identifiers and d is a dblink. No syntax checking is performed on the
dblink. If a dblink is specified, or if the name resolves to something with a dblink, then the object is not resolved, but the schema,
part1, part2, and dblink OUT parameters are filled in. a, b, and c may be delimited identifiers, and may contain NLS characters
(single and multi-byte).
schema Schema of the object: c. If no schema is specified in name, then the schema is determined by resolving the name.
part1 First part of the name. The type of this name is specified part1_type (synonym, procedure, or package).
part2 If this is non-NULL, then this is a procedure name within the package indicated by part1.
dblink If this is non-NULL, then either a database link was specified as part of name or name was a synonym that resolved to something
with a database link. In this latter case, part1_type indicates a synonym.
of execution are shown here for a context value of 0): SQL> exec snc ('EMP', 2)
Schema: SCOTT
SQL> @snc_test1 0 2: EMP
Error resolving "proc" with context 0
ORA-20005: ORU-10034: context argument SQL> exec snc ('EMP', 3)
must be 1 or 2 or 3 or 4 or 5 or 6 or 7 Error resolving "EMP" with context 3
ORA-06564: object EMP does not exist
Listing 1. Version 2 of SNC, the smarter program. -- If the object number is NULL,
-- name resolution failed.
IF object_number IS NULL
CREATE OR REPLACE PROCEDURE snc (NAME_IN IN VARCHAR2) THEN
IS DBMS_OUTPUT.put_line ( 'Name "'
-- Maximum context allowed by NAME_RESOLVE || NAME_IN
c_max_context CONSTANT PLS_INTEGER := 8; || '" does not identify a valid object.'
-- Test context value );
l_context PLS_INTEGER := 0; ELSE
-- DBMS_OUTPUT.put_line ('Context: ' || l_context);
l_resolved BOOLEAN := FALSE; DBMS_OUTPUT.put_line ('Schema: ' || sch);
--
-- Variables to hold components of the name. IF part1 IS NOT NULL
sch VARCHAR2 (100); THEN
part1 VARCHAR2 (100); DBMS_OUTPUT.put_line (
part2 VARCHAR2 (100); name_for_type (part1_type) || ': ' || part1);
dblink VARCHAR2 (100);
part1_type NUMBER; IF part2 IS NOT NULL
object_number NUMBER; THEN
DBMS_OUTPUT.put_line ('Name: ' || part2);
-- Collection to hold object type names END IF;
-- for type numbers ELSE
TYPE names_tt IS TABLE OF DBMS_OUTPUT.put_line (
all_objects.object_type%TYPE name_for_type (part1_type) || ': ' || part2);
INDEX BY BINARY_INTEGER; END IF;
names_t names_tt; IF dblink IS NOT NULL
-- THEN
-- The type numbers I now know about DBMS_OUTPUT.put_line ('Database Link:'
table_type CONSTANT PLS_INTEGER := 2; || dblink);
view_type CONSTANT PLS_INTEGER := 4; END IF;
synonym_type CONSTANT PLS_INTEGER := 5; END IF;
procedure_type CONSTANT PLS_INTEGER := 7; EXCEPTION
function_type CONSTANT PLS_INTEGER := 8; WHEN OTHERS
package_type CONSTANT PLS_INTEGER := 9; THEN
DBMS_OUTPUT.put_line ('SNC Error resolving "'
PROCEDURE initialize || NAME_IN);
IS DBMS_OUTPUT.put_line (
BEGIN DBMS_UTILITY.format_error_stack);
names_t (table_type) := 'Table'; END snc;
names_t (view_type) := 'View'; /
names_t (synonym_type) := 'Synonym';
names_t (procedure_type) := 'Procedure';
names_t (function_type) := 'Function'; When I run it for my expanded set of objects
names_t (package_type) := 'Package';
END initialize; (snc_test2.sql), I see that tables and views are now
handled intelligently:
FUNCTION name_for_type (type_in IN PLS_INTEGER)
RETURN VARCHAR2
IS Context: 2
BEGIN Schema: SCOTT
RETURN names_t (type_in); Table: TAB
EXCEPTION
WHEN NO_DATA_FOUND Context: 2
THEN Schema: SCOTT
RETURN type_in; View: VU
END name_for_type;
BEGIN
initialize; So SNC has gotten more flexible, and I’m tempted to
/* Break down the name into its components */ say that I’m now ready to use it against a wide array of
WHILE (NOT l_resolved AND l_context <= c_max_context) inputs (types of objects and different ways of naming
LOOP
BEGIN objects, and particularly with the use of synonyms). Yet
DBMS_UTILITY.name_resolve (NAME_IN I hesitate, because for all the cool qualities of SNC, it’s
,l_context
,sch still just a demonstration program. My efforts with this
,part1 program, however, aren’t just for demonstration purposes
,part2
,dblink or simply to write an article. I need an enhanced version
,part1_type of NAME_RESOLVE in Qnxo that works under all
scott.pkg ==> Schema: SCOTT Package: PKG When I use this to display the synonyms I created in
ps_pkg ==> Schema: SCOTT Package: PKG
ps_ls_pkg ==> Schema: SCOTT Package: PKG the previous section, I see the following:
Name "ps_ps_pkg" does not identify a valid object.
SQL> BEGIN
So it seems we’ve found a problem with 2 qnr.show_synonym ('SCOTT', 'ls_pkg');
3 qnr.show_synonym ('SCOTT', 'ps_pkg');
NAME_RESOLVE: It doesn’t properly resolve multiple 4 qnr.show_synonym ('PUBLIC', 'ps_pkg');
layers of synonyms in the specific case when one of the 5 qnr.show_synonym ('SCOTT', 'ls_ls_pkg');
6 qnr.show_synonym ('SCOTT', 'ls_ps_pkg');
“inner” synonyms is a PUBLIC synonym. Let’s see if we 7 qnr.show_synonym ('SCOTT', 'ps_ls_pkg');
can understand why this is happening—and then see 8 qnr.show_synonym ('PUBLIC', 'ps_ls_pkg');
9 END;
how we can fix it within QNXO_NAME_RESOLVE. 10 /
Synonym "ls_pkg" is defined as:
Owner: SCOTT
The problem with public synonyms Synonym name: LS_PKG
To figure out what’s going on, I’ll need to query the Table owner: SCOTT
Table name: PKG
contents of ALL_SYNONYMS to show me synonym Database link:
definitions. Rather than run standalone queries, I’ll
"SCOTT.ps_pkg" is not a synonym.
create a PL/SQL procedure to take care of the details.
And now I face a quandary: I’ve so far created two Synonym "ps_pkg" is defined as:
Owner: PUBLIC
standalone procedures, QNXO_NAME_RESOLVE and Synonym name: PS_PKG
QNXO_SHOW. Now I’m going to create another Table owner: SCOTT
Table name: PKG
standalone procedure to show synonyms? I don’t like all Database link:
of these separate procedures clogging up my object list.
Synonym "ls_ls_pkg" is defined as:
So I’ll move them (and create them) all in a single Owner: SCOTT
package named QNR. This package is defined in two Synonym name: LS_LS_PKG
Table owner: SCOTT
files, qnr.pks and qnr.pkb. I show in Listing 4 only the Table name: LS_PKG
show_synonyms procedure that’s new. There’s nothing Database link:
particularly challenging about it: Query the row and then Synonym "ls_ps_pkg" is defined as:
display the results. Owner: SCOTT
Synonym name: LS_PS_PKG
Table owner: SCOTT
Table name: PS_PKG
Listing 4. The implementation of show_synonyms. Database link:
PROCEDURE name_resolve (
Listing 8. Testing the synonym_resolve procedure. NAME IN VARCHAR2
,SCHEMA OUT VARCHAR2
,part1 OUT VARCHAR2
CREATE SYNONYM ls_pkg FOR pkg; ,part2 OUT VARCHAR2
CREATE PUBLIC SYNONYM ps_pkg FOR pkg; ,dblink OUT VARCHAR2
CREATE SYNONYM ls_ls_pkg FOR ls_pkg; ,part1_type OUT NUMBER
CREATE PUBLIC SYNONYM ps_ps_pkg FOR ps_pkg; ,object_number OUT NUMBER
CREATE SYNONYM ls_ps_pkg FOR ps_pkg; )
CREATE PUBLIC SYNONYM ps_ls_pkg FOR ls_pkg; IS
PROCEDURE resolve_in_loop (NAME_IN IN VARCHAR2)
SET serveroutput on format wrapped IS
-- Maximum context allowed by NAME_RESOLVE
DECLARE c_max_context CONSTANT PLS_INTEGER := 8;
PROCEDURE TEST (NAME IN VARCHAR2) -- Test context value
IS l_context PLS_INTEGER := 0;
SCHEMA all_objects.owner%TYPE; --
object_name all_objects.object_name%TYPE; l_resolved BOOLEAN := FALSE;
BEGIN BEGIN
qnr.synonym_resolve (NAME, SCHEMA, object_name); /* Break down the name into its components */
dbms_output.put_line ( 'Synonym "' WHILE (NOT l_resolved
|| NAME AND l_context <= c_max_context)
|| '" resolved to "' LOOP
|| SCHEMA BEGIN
|| '.' DBMS_UTILITY.name_resolve (NAME_IN
|| object_name ,l_context
|| '"' ,SCHEMA
); ,part1
END; ,part2
BEGIN
TEST ('ls_pkg'); Continues on page 15
Using Autonomous
Transactions
Moru Nuhamovici
With the introduction of autonomous transactions in debited must be in $200 increments. So, an attempt to
Oracle8i, a whole new series of possibilities became available debit more than $200 would be logged and not allowed.
to the user. Oracle has always used autonomous transactions The myaudit_table will store all attempts at trying to
for internal purposes, but it hasn’t exposed this feature to break the rule of debiting more than $200.
the general public before. In this article, Moru Nuhamovici
explains the benefits of autonomous transactions and shows SQL> create table myaudit_table
2 (
how this feature can be exploited. 3 table_name varchar2(30),
4 user_name varchar2(30) default user,
5 timestamp date default sysdate,
P
RIOR to Oracle8i, there was no way to execute a 6 comments varchar2(4000)
transaction separate from the current transaction— 7 );
1 row created.
Autonomous transactions are typically used for
auditing, often defined inside triggers to catch a user SQL> insert into clienttransactions
values (3, 0, 3000, 300, 3000);
trying to modify the data in some manner. If the
transaction that was trying to modify the data didn’t 1 row created.
complete and failed, the independent autonomous SQL> select * from clienttransactions;
transaction would still succeed and catch the attempt at
CLIENTID DEBIT CREDIT OVERDRAFT BALANCE
modifying the data. A common reason why the original ---------- ---------- ---------- ---------- ----------
transaction would fail would be properly enforced 1 0 1000 100 1000
2 0 2000 200 2000
security that prevents the user from performing 3 0 3000 300 3000
unauthorized actions.
Let’s take a look at a couple of examples that Next, I create a function that returns the maximum
illustrate this usage. amount being debited. Creating the function to isolate
this rule makes it easier to change this later on.
Performing I/O on an Update statement
Suppose I have a clienttransactions table that records the create or replace function max_debit
return number as
amount credited, the amount debited, and the overall max_debit number(10);
balance. I have a rule requiring that the amount being begin
At this point, the error returned tells me that I can’t create or replace view v_clienttransactions
deduct more than $200. What’s not known to a user who as
select Clientid, Debit, Credit, Overdraft
tries to perform this transaction is that this attempt has , LogSelects('ClientTransactions', 'Balance'
been logged. Let’s take a peek at the myaudit_table and , ClientId, Balance) Balance from clienttransactions;
/
see what’s been caught:
This is the key technique here: I’m using a view to
SQL> select table_name, timestamp, comments
from myaudit_table; wrap the clienttransactions table; the users aren’t
querying the table directly. By doing this, I’m able to
TABLE_NAME TIMESTAMP COMMENTS include the function LogSelects and alias it with the
---------------------- --------- --------------------- name Balance. This will be transparent to the user.
ClientTransactions 27-JUN-04 Attempt to deduct 500
Now I’ll create my two users and test the theory out.
You can see that the trigger caught the attempt SQL> create user honestsam identified by honestsam;
to deduct more than $200, as well as preventing it
User created.
from happening.
SQL> create user sneekypete identified by sneekypete;
Performing I/O on a Select statement User created.
The ability to catch attempts to modify data is great, but
SQL> grant create session to honestsam, sneekypete;
what about catching attempts to read data? In some
situations it would be nice to be able to track who has Grant succeeded.
Caveats
If you intend to use this feature frequently, be sure to
increase the limit on transactions within your database
initialization file, init.ora. When this feature is used
extensively, it can make troubleshooting a bit more
difficult, as sometimes you can be guessing about which
transactions are the ones currently active.
D:
Sometimes the autonomous transaction will report
that users saw something they really didn’t. Suppose GE
A
I wanted to sum the balance of all clients for a report: PA
TER
R OFT
QU REALS
SQL> connect honestsam/honestsam;
Connected. A
SQL> select sum(balance) from test.v_clienttransactions;
SUM(BALANCE)
------------
6000
A
LL errors in Oracle Reports belong to a standard
type of REP and are characterized by Error Type This is caused by the placement of a field inside a
(indicates whether the error is a warning message repeating frame that’s not in sync with the group of the
or an actual error message), Error Code (an integer associated source column in the data model.
indicating the error number), and Error Text (the text of Normally, Oracle Reports halts the execution of the
the error message). report and raises its own error.
There’s a set of procedures, functions, and exceptions
to handle errors in Reports. Let’s first look at a brief Errors raised out of exceptions from trigger/PL/SQL code
overview of the primary ones before delving into PL/SQL code can be incorporated into a report by using
examples of their use. any one of the following:
• PL/SQL query in the data model
Procedures and functions • Formula column in the data model
The SRW package contains a procedure called MESSAGE • Validation code of a report parameter
that allows you to define a customized error message, • Group filter in the data model
which can be application-specific. • Format trigger of a frame, repeating frame, field, or
SQLCODE and SQLERRM are functions that return boilerplate text
the code and text for standard PL/SQL exceptions. • Report triggers such as BEFORE PARAMETER
FORM, AFTER PARAMETER FORM, BEFORE
Exceptions REPORT, BETWEEN PAGES, and AFTER REPORT
PROGRAM_ABORT will prevent further Reports
processing as the result of an error. This is also part of the Errors raised out of exceptions from trigger/
SRW package and has to be raised explicitly with the PL/SQL code can be handled in the exception handler
RAISE command. using the SQLCODE and SQLERRM functions. These are
I’ll classify the errors raised in Reports into the SQL and/or PL/SQL exceptions that are caused by the
following broad categories: failure of SQL DML statements or PL/SQL statements.
• Errors raised out of failure of Report object You should always code an exception handling section
properties. with the WHEN OTHERS clause, wherever SQL and/or
• Errors raised out of exceptions from trigger/ PL/SQL is involved. A typical exception handling section
PL/SQL code (that is, failure of DML statements can be as follows:
or PL/SQL errors).
EXCEPTION WHEN OTHERS THEN
SRW.MESSAGE(100, TO_CHAR(SQLCODE)||' '||SQLERRM);
These errors can and should be handled by writing RAISE SRW.PROGRAM_ABORT;
NAME_RESOLVE... THEN
resolve_in_loop (l_schema || '.' || l_name);
END IF;
Continued from page 8 END try_as_synonym;
BEGIN
resolve_in_loop (NAME);
,dblink
,part1_type IF object_number IS NULL
,object_number THEN
); try_as_synonym (NAME);
l_resolved := TRUE; END IF;
EXCEPTION EXCEPTION
WHEN OTHERS WHEN OTHERS
THEN THEN
l_context := l_context + 1; try_as_synonym (NAME);
END; END name_resolve;
END LOOP;
END resolve_in_loop;
First, I’ll move my looping call to NAME_RESOLVE
PROCEDURE try_as_synonym (NAME_IN IN VARCHAR2)
IS
into its own local procedure, resolve_in_loop. Then,
l_schema all_objects.owner%TYPE; I’ll call another local procedure that tries to resolve a
l_name all_objects.object_name%TYPE;
BEGIN
synonym, in the cases when NAME_RESOLVE has failed.
-- Try to resolve as synonym. The main body of my qnr.name_resolve program is now
synonym_resolve (NAME_IN, l_schema, l_name);
short and sweet! My try_as_synonym procedure resolves
IF l_name IS NOT NULL the synonym and then tries to resolve that base object
Pinnacle, A Division of Lawrence Ragan Communications, Inc. ▲ 800-493-4867 x.4209 or 312-960-4100 ▲ Fax 312-960-4106
For access to current and archive content and source code, log in at www.pinnaclepublishing.com.
Phone: 800-493-4867 x.4209 or 312-960-4100 Copyright © 2004 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
Email: PinPub@Ragan.com case of brief quotations embodied in critical articles and reviews) without the prior
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.