Skip to Main Content
  • Questions
  • Understand the concepts but to define it to others

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, sam.

Asked: November 25, 2001 - 3:45 pm UTC

Last updated: April 28, 2008 - 11:05 am UTC

Version: 8.1.7

Viewed 1000+ times

You Asked


Tom

1.I have used ref cursors, varrays, and nested tables.

But when Iam asked to define then Iam at a loss.

Can you define the above 3 for me( a small comparision example for varray and nested table).

2.The same with nocopy parameter , actually the difference between in , out , inout and nocopy parameters. I know the examples and I have done it, but what I want is definition. Without a computer and without a black board, how do you define then( say when asked in an interview).

Thank you

and Tom said...

1) a ref cursor is a cursor -- its a pointer to a cursor but a cursor none the less.

Their primary uses are:

o returning result sets from stored procedures to any client application
o performing dynamic SQL in plsql

Varrays and Nested Tables are close cousins of eachother. When used in PLSQL they behave much like an array would. A varray is bounded (has a max number of items) whereas a nested table is not (bounded more or less by RAM in PLSQL when used as an array).

When used in CREATE TABLE statements for permanently stored objects, they allow you to keep either an ordered array of data (varray's) or an un-ordered collection of data (nested tables). A varray is physically stored in a LOB as packed data whereas a nested table is stored in a real physical child database table.


2) NOCOPY says to pass that parameter by REFERENCE not by value. IN only parameters are ALWAYS passed by reference (a pointer to the parameter is passed, not the parameter value). This is because IN parameters cannot be written to, hence passing the reference is "safe".

Normally IN OUT and OUT parameters are passed using "copy" semanatics. An IN OUT parameter is passed by copying the IN value into a temporary -- the temporary is used in the procedure/function and then (upon SUCCESSFUL completion of the routine) its value is copied back to the original parameter that was passed (two copies). An OUT parameter is not copied on the way into the procedure -- however a temporary variable is still used in the routine and on the way out (up SUCCESS) the temporary variable's value is copied back into the parameter that was passed initially (one copy).

If you pass a varible with NOCOPY -- a pointer is passed. For an IN OUT parameter, this means that when you modify the parameter -- its value is IMMEDIATELY modified, we do not copy to a temporary variable. What this means is that any modification you make to it in the routine is made to the parameter right then -- not when the procedure succesfully completes. This means side effects from a failed procedure can be visible to the caller (and this is not normally so). If you have just a small routine such as:

procedure p( x in out NOCOPY number ) is
begin
x := 55;
raise program_error;
end;

Then you call it like this:

declare
y number := 0;
begin
p(y);
exception when others then
dbms_output.put_line(y);
end;

that will print 55 -- not 5 (it will print 5 if you do not use NOCOPY since the values are ONLY copied upon SUCCESS).

It can be even more tricky with OUT parameters. OUT parameters are ALWAYS modified -- even if the procedure you called never touches them. Simply change P to be:

procedure p( x out NOCOPY number ) is
begin
raise program_error;
end;

that doesn't modify x at all, now if you execute:

declare
y number := 0;
begin
p(y);
exception when others then
dbms_output.put_line('y='||y);
end;

that'll print "y=" -- y will be set to NULL.

So, you cannot just go in and put NOCOPY everywhere as this side effect can change the existing behaviour of your code. NOCOPY is ONLY useful on truly large objects like tables and collections. It doesn't make nearly as much sense to use NOCOPY on a simple NUMBER/DATE type or small strings as it does on these large variables (doesn't make sense on a LOB either as the lob locator itself is small).



Rating

  (10 ratings)

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

Comments

Marc Blum, November 26, 2001 - 3:51 am UTC

It's always the same: decided to lurk asktom and found some very interesting article. Conclusion: spend 30min every day reading asktom as part of your self-education-program

No doubt! It is Sea-Knowledge of Oracle

Samik Nath, November 26, 2001 - 5:55 am UTC

Great Page

Understand the concepts but to define it to others

sanjai, November 26, 2001 - 2:42 pm UTC

Great page. I agree all of us should spend atleast 30 min reading askTom. I get to learn the best of oracle stuff here.

Tom, thanks for all your help.

A reader, April 24, 2002 - 2:10 pm UTC


Cleared my confusion

BK, July 23, 2002 - 5:13 pm UTC

Great article ! some othere article suggested to search before asking new question, that really worked. I'd confusion about SP parameters and was wondering if the values are passed by reference or values. I've been developing custom API's for oracle apps and make use of large Record types and had doubt about performance implications of all this record types passed by value. If you could give some more idea about performance implications of using Record types when apssed as parameters and how to manage it in a better way then it would be really helpful. API's are used for real-time integration between apps and website so sub second improvement would also help. Is it better to use NOCOPY when record types are passed as parameter ? If my record type being passed as parameter to the SP has 10 attributes and I initialize 5 of them before passing it to the procedure, then will it pass only initialzed attributes in a record type or all(10) of them ?
Thanks,

Tom Kyte
July 23, 2002 - 9:12 pm UTC

IN parameters = REFERENCE. passed by reference (pointer)

OUT parameters = VALUE. copy on output (temporary set up, filled in a copied on success)

IN OUT = VALUE. copy to temporary, copy from temporary (passed by value)


Use NOCOPY and all are passed by reference (search this site for nocopy to read about the CAVEATS with that! Better -- it depends. Different is more like it. It has SIDE EFFECTS)

Thanks for the simple, solid definitions!

Robert, July 24, 2002 - 9:18 am UTC


ToM, YOU THE MAN!

A reader, July 24, 2002 - 11:44 am UTC

:-) You are going to live 100 years, you have blessing from all of us! Great job you are doing!

sorry for the future generations :o(

Robert Chin, July 24, 2002 - 1:30 pm UTC

>>:-) You are going to live 100 years, you have blessing from all of us!

Makes me feel sorry for the future generations...
(circa Oracle 38i ?)
who's gonna be crusading for Bind Variables ? who's gonna be pointing them down the correct path to technical enlightenment in Oracle ?...who's gonna write another book as excellent as "Expert 1-1" ?

But for now...Tom, please confirm this:
If I miss just one and use literal,
out of n spots where BV should be used..
e.g.
Open myRefCur for 'select * from emp where empno = ' || x || ' and ename = :a and sal > :b' Using myBV1, myBV2

This will totally negate the use of myBV1, myBV2, right ?
That is,this will be a total re-hardparse every time, right ?
Thanks


Tom Kyte
July 24, 2002 - 10:53 pm UTC

pretty much -- assuming that EMPNO is the primary key, every query would be unique.

functions returning NOCOPY object

matthias, April 21, 2008 - 3:38 am UTC

Hi Tom,

I've got a NOCOPY-related question about functions returning an object type.

Please consider:

-- "Singleton" class
create or replace type myObj as object
(

anAttribute varchar2(10),

constructor function myObj
(self in out nocopy myObj
)
return self as result,

-- print anAttribute
member procedure printAttribute
(self in out nocopy myObj,
msg in varchar2
)

);
/


-- package to store the global myObject
Create or Replace Package myGLOB as

-- this is where I'd like to store my object
gObj myObj;

End myGLOB;
/


create or replace type body myObj as

constructor function myObj
(self in out nocopy myObj
)
return self as result is
begin
anAttribute := 'initial';
return;
end;

member procedure printAttribute
(self in out nocopy myObj,
msg in varchar2 ) is
begin
dbms_output.put_line(msg||':'||anAttribute);
end;

End;
/


create or replace procedure popRef
(ref in out nocopy myObj) is
begin
if myGLOB.gObj is null then
myGLOB.gObj := myObj();
myGLOB.gObj.printAttribute('just created');
end if;
ref := myGLOB.gObj;
end;
/



create or replace procedure test as
o myObj;
begin

popRef(o);
o.anAttribute := 'new';

o.printAttribute('ok - "new"');

--Q1: stills shows "initial" - why?
myGLOB.gObj.printAttribute('should also be "new"');

end;
/


this is my output:
--------------------------

OOLTEST@PRJ_JAMES> exec test
just created:initial
should be "new" now:initial




create or replace function getRef
return myObj is
begin
return myGLOB.gObj;
end;
/


begin
-- Q2: this will throw PLS-00363:expression "myObj.getRef" cannot
-- be used as an assignment target --- why ???
getRef().printAttribute('PLS-00363');
end;
/

*
FEHLER in Zeile 4:
ORA-06550: Zeile 4, Spalte 3:
PLS-00363: Ausdruck 'GETREF' kann nicht als Zuweisungsziel benutzt werden
ORA-06550: Zeile 4, Spalte 3:
PL/SQL: Statement ignored


thanks[1000]
Tom Kyte
April 23, 2008 - 4:41 pm UTC

... --Q1: stills shows "initial" - why?
myGLOB.gObj.printAttribute('should also be "new"');

...

why would myglob (variable 1) be affected by modifications to o (variable 2)?? Not sure what you mean here.


q2 - that code does not execute, it must be part of something larger???


I frankly did not follow this very well, sort of confusing what you are trying to do.

do you see something different with and without nocopy?

what I am trying to to

matthias, April 24, 2008 - 3:13 am UTC

I'm trying to "store" a single object in a package variable.

Then I'd like to have a function or procedure that returns a NOCOPY-reference of that object, thus hiding the existence of the package variable.

In the end I'd like to use "getRef().x.y.z." to access my top-level object and its attributes. I know I could use myGLOB.myObj.x.y.z all the time, but then I cant be sure that the object has already been created.

I think it can be easyly done by using "real" object table REFs plus the built-in ref() and deref() but I'd like to avoid the O/R-mapping und do it all in memory....

thanks again.
Tom Kyte
April 28, 2008 - 11:05 am UTC

...
Then I'd like to have a function or procedure that returns a NOCOPY-reference
of that object, thus hiding the existence of the package variable.

.....


not going to happen. A function returns a value by "value" (return SOMETHING).

A procedure can have an in/out parameter (meaning the INVOKER sends you a pointer, you do not 'return' them anything, you might modify what they are pointing to)...


ref and deref take object id's - not really truly 'pointers' in the sense of a "pass by value, pass by reference". deref would return the object instance - by value.



You can use elaboration code in a package to "make sure" the object has been 'created'

you can use attributes in the object itself to signify "i've been initialized" as well

what you are trying to do just doesn't make sense (neither in the context of a function or in the context of an in/out parameter)

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