Struggling as I am to find time to write items for the blog, I was pleased to get an email yesterday from someone who had discovered an interesting little feature of pl/sql programming and wanted to pass it on to me.
I thought that other people (PL/SQL developers in particular) might find it useful, so I asked if I could reproduce the email verbatim on my blog. The answer was yes – so here’s my first “guest blog” item, courtesy of Jason Bucata.
PL/SQL Naming Discovery
I’ve been going through some of the PL/SQL code from Oracle Applications to see how a few things work. While digging around, I discovered a very useful feature of PL/SQL that, as far as I know, isn’t documented anywhere.
Suppose you’ve got some variables, and a query against a table. The table happens to have columns with the same names as some of your variables. You want to reference the variables in the query.
It’s easy enough to specify that you want the columns: Use a table alias. (Or leave it off, since that’s the default behavior anyway, though I think it’s clearer to be explicit.) But if you want to use the variables, I’ve always either renamed the variables or bundled them into a record (or occasionally an object type).
But it turns out that you can qualify the variable name by using the name of the procedure or function!
The following code works on 9.2.0.8, at least:
set serveroutput on
declare
procedure p is
dummy char(1) := 'X';
cnt pls_integer;
begin
select count(*)
into cnt
from dual
where dual.dummy = p.dummy;
if cnt = 1 then
dbms_output.put_line('It worked');
else
dbms_output.put_line('It failed');
end if;
end p;
begin
p;
end;
/
Unfortunately the examples in the PL/SQL User’s Guide and Reference, Appendix D, only show cases where the variable is a public package variable, and so is visible to the outside. I always expected that to work — we all know to reference public package variables with <package_name>.<variable_name> — but I didn’t expect that to work with local variables in a procedure. Until today, I’ve never seen code referencing <procedure_name>.<variable_name> in any context.
It also turns out (this from looking at Appendix D) that block labels can be used, too. See the following example. Even though this is documented, it’s very underpublicized, IMHO.
set serveroutput on
begin
<<p>>
declare
dummy char(1) := 'X';
cnt pls_integer;
begin
select count(*)
into cnt
from dual
where dual.dummy = p.dummy;
if cnt = 1 then
dbms_output.put_line('It worked');
else
dbms_output.put_line('It failed');
end if;
end;
end;
It’s also useful to get at variables in an outer scope that are masked by variables of the same name in an inner scope, but in practice I don’t think I’ve ever seen anybody a) reuse variable names in nested scopes and b) want to use both variables in the inner scope. That just seems to be a good programming practice, to avoid choosing names that way. I think that’s why this is so obscure: Good code doesn’t need that feature, at least in pure PL/SQL.
You might want to spread the word. This can be very useful to those of us who frequently embed SQL in PL/SQL code.
Jason B.
This behaviour is documented in chapter 2: PL/SQL Language Fundamentals, subsection “Scope and Visibility of PL/SQL Identifiers” of the PL/SQL Language Reference Guide:
http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28370/fundamentals.htm#LNPLS00204
Comment by dombrooks — September 5, 2008 @ 9:06 am UTC Sep 5,2008 |
IMHO it`s a very bad practice naming variables like table column names
code conventions save all of us ))
Comment by drnk — September 5, 2008 @ 9:32 am UTC Sep 5,2008 |
Indeed, an object lesson in prefixing variables, whether local or global, appropriately. Thanks Jonathan.
Comment by SeánMacGC — September 5, 2008 @ 10:31 am UTC Sep 5,2008 |
This is very interesting. I’ve been using PL/SQL for a decade and didn’t know this. I will definitely try this out.
One thing though: I don’t get the previous comment that says that this is a “lesson in prefixing variables”. It is more a lesson in *not* prefixing variables and using namespace notation instead. Any intelligent means (like this feature) to eliminate variable name prefixes is welcome in my book.
I like using “p.dummy” a heck of a lot better than “v_dummy”.
Comment by Michael O'Neill — September 5, 2008 @ 12:51 pm UTC Sep 5,2008 |
I always name the variable the same as the COLUMN. Very easy to follow things and context is always clear. The purpose of prefixing is for classing (until somebody went horribly wrong http://www.joelonsoftware.com/articles/Wrong.html). Being bale to class with the PROCEDURE or label’s name is excellent.
Comment by Brian Tkatch — September 5, 2008 @ 1:06 pm UTC Sep 5,2008 |
I’m with Michael. “p.dummy” explicitly tells you where the value is coming from, “v_dummy” (or “l_dummy” as some of my peers have written) requires checking where it’s defined.
I’d actually seen this in the documentation long ago, but forgotten it. Thanks for the refresher!
Comment by Stew — September 5, 2008 @ 6:41 pm UTC Sep 5,2008 |
So, should I call all my procedures “p”, “q”, “r” and “s”? Does that make my code more legible? I like more descriptive names, which means if I prefix my variables then my SQL gets longer and harder to read.
Also, using a feature that is little known will hinder, not help, others who read my code.
I get along OK with Tom Kyte’s convention : g_ prefix for “globals” (package or package body scope), p_ for parameters and l_ for local variables. Of course, if I ever run across a column name that starts with one of these prefixes I will happily use what I have learned here
Comment by Stew Ashton — September 6, 2008 @ 8:40 am UTC Sep 6,2008 |
Re comment #1: Good pointer there. Prior to 11g, the docs weren’t nearly as thorough. 9.2’s docs didn’t cover it like that when I dug into it. Glad to see that Oracle is helping to get the word out.
Comment by Jason Bucata — September 8, 2008 @ 8:43 am UTC Sep 8,2008 |
Used it in Oracle 7.3
Comment by lascoltodelvenerdi — September 9, 2008 @ 7:39 am UTC Sep 9,2008 |
Don’t see why it should either be a) prefixing, OR b) namespace notation. Prefixing with ‘g_’, ‘l_’ and ‘p_’ makes sense, and where namespace conflicts arise, then further qualify by prefixing with the name of the related object.
Comment by SeánMacGC — September 11, 2008 @ 9:13 am UTC Sep 11,2008 |
Here’s a coincidence:
Looking at Oracle Magazine (sept/oct issue), I see that Steve Fueurstein’s article comments that:
This approach has always been a recommended best practice; with fine-grained dependency tracking, it is more important than ever.
The fine-grained dependency tracking is a feature of 11g that allows Oracle to minimise the cascade of invalidations and recompilations that need to occur when you change an object.
Comment by Jonathan Lewis — October 1, 2008 @ 11:37 am UTC Oct 1,2008 |