Skip to Main Content
  • Questions
  • Name resolving for equally named variables and table fields

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Peter.

Asked: August 04, 2005 - 11:16 am UTC

Last updated: August 17, 2005 - 1:29 pm UTC

Version: 9.2

Viewed 1000+ times

You Asked

Hi,

i have the following problem with name resolving in PL/SQL and I'm not sure wich is the right way to avoid it:

I have table T1

CREATE TABLE T1 (KEY NUMBER);
INSERT INTO T1 (KEY) VALUES (1);

and a procedure:

CREATE OR REPLACE PROCEDURE Myfunc IS
vPos NUMBER :=1;
rt1Rec T1%ROWTYPE;

BEGIN
SELECT * INTO rt1Rec
FROM T1
WHERE T1.KEY = vPos;
END;

I can execute the procedure Myfunc without problem.
In a next step i have to add a field to my table T1

ALTER TABLE T1 ADD VPOS NUMBER;

By "accident" the new table field has the same name like the variable I declared in Myfunc !
The package will become invalid but can be recompiled without any error.

When I execute procdure Myfunc again it will raise a NO DATA FOUND excecption because, i assume, in the select statement the vPos expression is resolved to T1.VPOS instead to the variable declare in Myfunc.

This means a existing, working procedure will not work anymore by just adding a table field ! What is the correct way to progamm Myfunc so this problem will never occour ? (except scanning the source code of a whole application everytime a field is added to a table ?)

I tried this:

CREATE OR REPLACE PROCEDURE Myfunc IS
vPos NUMBER :=1;
rt1Rec T1%ROWTYPE;

BEGIN
SELECT * INTO rt1Rec
FROM T1
WHERE T1.KEY = Myfunc.vPos;
END;

This seems to work, but is this the "best practice way" ?
And shouldn't the compiler give out a error like e.g. "ambiguous defined column" ?
Thanks in advance for your help and your tips !

Peter


and Tom said...

If you've seen my code, you know that all of my plsql variables start with:


p_ for a parameter:

create or replace procedure something( P_in_date date )

l_ for a local variable:

as
l_data number;
begin

g_ for package global variables:

l_data := my_pkg.g_data_default
......


And I've never been tempted to start a column name with p_, l_, g_


Else, if you do - you have that headache from above and must use the procedure/package (the object name) to qualify it.


It is *not* ambigous, it is just an overridden scope. Not any different than:


is
l_data number;
begin
...
declare
l_data number; -- hides the other l_data
begin
.....
for l_data in 1 .. 10 -- hides the other one that is hiding the first
loop
....

Rating

  (4 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

variable prefixing

Bart, August 05, 2005 - 3:37 am UTC

I split g_ variables into

a_ for package variables
o_ for package body variables

because I find the difference very significant.

(I seldom use a_ variables ... - I'm more and more using get/set procedures and functions)





Tom Kyte
August 05, 2005 - 11:04 am UTC

curious, p=parameter, l=local, g=global, what do A and O stand for?

Answer

Bart, August 10, 2005 - 5:46 am UTC

Well, obviously the first character won't make much difference.

As an alternative I find this the most intuitive choice. I know it's very personal. But if I see o_ I immediately know it's a package body. The O is singing at me: 'Boooddyyy'.


But this is the answer:

p A ckage
package b O dy




Tom Kyte
August 10, 2005 - 10:19 am UTC

Ahh, see, I would have used

s_ for spec
b_ for body.

aargh

Bart, August 12, 2005 - 10:19 am UTC

I misgrowned with b_ as cursor parameters from a standard I had to follow in previous Jobs '(I'm hired by Oracle Netherlands for their Health Insurance Application eZorg).

I suppose they wanted to distinct between procedure parameters (p_) and cursor parameters (b_ from bind I suppose).

So no b_ for me.

Tom Kyte
August 13, 2005 - 8:53 am UTC

b_ from bind? p_ are 'binds' normally to ;)

Elaborate more

Bart, August 17, 2005 - 5:46 am UTC

I read all about binds on your site.
I know (we all do, don't we...) that in pl/sql binding is implicit (not talking about -wrongly implemented- dynamic stuff here - execute immediate followed by literals...etc.)


I had to change to b_ because of Oracle Netherlands!!


But it isn't too bad. Let's proceed on this tasty topic.
Let's give some small, concise ( ;) )examples to show it's use (oh, and it's also an hypothetical one).
The changes might look subtle, non-relevant. However, I think that they're not.

What follows now are four procedures. Pick out the best:

1.
create or replace procedure without_b_1
(p_name_selection in varchar2)
is
cursor c_obj
is
select object_name
from user_objects
where object_name like p_name_selection
;
begin
for r_obj in c_obj
loop
dbms_output.put_line (r_obj.object_name);
end loop;
end without_b_1;

2.
create or replace procedure without_b_2
(p_name_selection in varchar2)
is
cursor c_obj (p_name_selection in varchar2)
is
select object_name
from user_objects
where object_name like p_name_selection
;
begin
for r_obj in c_obj (p_name_selection => p_name_selection)
loop
dbms_output.put_line (r_obj.object_name);
end loop;
end without_b_2;

3.
create or replace procedure without_b_3
(p_name_selection in varchar2)
is
cursor c_obj (p_name_selection in varchar2)
is
select object_name
from user_objects
where object_name like c_obj.p_name_selection
;
begin
for r_obj in c_obj (p_name_selection => without_b_3.p_name_selection)
loop
dbms_output.put_line (r_obj.object_name);
end loop;
end without_b_3;


4.
create or replace procedure with_b_4
(p_name_selection in varchar2)
is
cursor c_obj (b_name_selection in varchar2)
is
select object_name
from user_objects
where object_name like b_name_selection
;
begin
for r_obj in c_obj (b_name_selection => p_name_selection)
loop
dbms_output.put_line (r_obj.object_name);
end loop;
end with_b_4;
/

The fourth is my personal favorite NOW (might change). The third, well, on arguments maybe second-best, but feels very unnatural. I am sure most people have to take a second look on that one ;)
The second is obscure. Very prone to errors. Scoping issues here. Happens often with package/package body variables AND local variables in procedures (ran into some in real life). The first is ok, but as a rule (of thumb ;) ) I prefer passing data to show input/output - very important! This applies to cursors as well (although parameters are always 'in' parameters)

I didn't mention another alternative, namely changing the NAME completely. It's big enough now.

I didn't invent it, I accustomed to this standard. I had to even if I didn't like it, but sometimes you don't like something first, and after a while you start seeing the advantages. Before b_, I personally used cp_ (cursorparameter), not bad either -even better maybe-.

(I don't use (+) anymore - it took a while but I think it's ugly to use (+) nowadays, I can't read code without parameternaming (=>), etc. ).

Or you just get used to it and stick with it even without seeing advantages.


Tom Kyte
August 17, 2005 - 1:29 pm UTC

I like #4 or


for x in ( select ..... )
loop


(no cursor at all ;)

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library