WELCOME, GUEST
Minimize
Blogger List

Steven Feuerstein Indicates Oracle ACE director status
PL/SQL Obsession

Guy Harrison Indicates Oracle ACE status
Database topics

Bert Scalzo Indicates Oracle ACE status
Toad for Oracle, Data Modeling, Benchmarking
Dan Hotka Indicates Oracle ACE director status
SQL Tuning & PL/SQL Tips

Valentin Baev
It's all about Toad

Ben Boise
Toad SC Discussions

Dan Clamage
SQL and PL/SQL

Kevin Dalton
Benchmark Factory

Peter Evans 
Business Intelligence, Data Integration, Cloud and Big Data

Vaclav Frolik  
Toad Data Modeler, Toad Extension for Eclipse

Devin Gallagher
Toad SC discussions

Anju Gandhi
Toad for Oracle

Stuart Hodgins
JProbe Discussions

Julie Hyman
Toad for Data Analysts

  Henrik "Mauritz" Johnson
Toad Tips & Tricks on the "other" Toads
  Mark Kurtz
Toad SC discussions
Daniel Norwood
Tips & Tricks on Toad Solutions
Amit Parikh
Toad for Oracle, Benchmark Factory,Quest Backup Reporter
Debbie Peabody
Toad Data Point
Gary Piper
Toad Reports Manager
John Pocknell
Toad Solutions
Jeff Podlasek
Toad for DB2
Kuljit Sangha
Toad SC discussions
Michael Sass 
Toad for DB2
Brad Wulf
Toad SC discussions
Richard To
SQL Optimization
  Toad Data Modeler Opens in a new window
Data Modeling
 
  Toad Higher Education
How Hi-Ed Uses Toad
  Real Automated Code Testing for Oracle
Quest Code Tester blog
  中文技术资料库
技术文章
 

Blogs

Toad World blogs are a mix of insightful how-tos from Quest experts as well as their commentary on experiences with new database technologies.  Have some views of your own to share?  Post your comments!  Note:  Comments are restricted to registered Toad World users.

Do you have a topic that you'd like discussed?  We'd love to hear from you.  Send us your idea for a blog topic.


Aug 9

Written by: StevenFeuersteinTW
Tuesday, August 09, 2011 6:56 AM  RssIcon

I received this request from a reader in July:
"Could you please explain why Oracle recommends that we not use OUT/IN-OUT parameters in functions?"
Actually, it's not just Oracle. Most "gurus" in the software world make the same suggestion. There are two key reasons for the recommendation that you should only return data through the RETURN clause of a function, not the parameter list. I sum up these answers here, and then I offer a section from Oracle PL/SQL Best Practices, 2nd edition, that explores the same topic using the "story" style of that book.
Two key reasons to use only IN parameters with functions:
  1. The whole point of a function is to return a value (whether it’s a single, scalar value or a composite, such as a record or a collection). If you also return data back through the parameter list with OUT or IN OUT arguments, the purpose and usage of the function will be obscured.
  2. A function that contains an OUT or IN OUT parameter cannot be called from within a SQL statement. Here's an example:

Perhaps you don't often run across the need to call your own application-specific functions inside SQL. I take advantage of this feature frequently in the backend and APEX code of the PL/SQL Challenge, a site that offers quizzes on PL/SQL, SQL and APEX.
So remember: just because Oracle let's you do something (like define an OUT parameter in a function's parameter list), doesn't mean that you should do it!
And now an excerpt from Oracle PL/SQL Best Practices, 2nd edition (Chapter 8, "Playing with Blocks"):
Where'd that data come from?
AKA: Functions should return data only through the RETURN clause.
Problem: Jasper returns data in a very confusing manner.
Jasper needs a program to retrieve several pieces of information about an excuse: the title, the author and the word count. In just a few moments he builds the following function:
FUNCTION excuse_title (
   excuse_id_in IN mfe_excuse.isbn%TYPE
 , author_out OUT mfe_excuse.author%TYPE
 , word_count_out OUT mfe_excuse.word_count%TYPE)
RETURN mfe_excuse.title%TYPE
IS BEGIN
   ... implementation unimportant! ...
END excuse_title;
And then he puts this function to use as follows:
PROCEDURE process_excuse (excuse_id_in IN mfe_excuse.isbn%TYPE)
IS
 l_title mfe_excuse.title%TYPE;
 l_author mfe_excuse.author%TYPE;
 l_word_count mfe_excuse.word_count%TYPE;
BEGIN
   l_title := excuse_title (l_id, l_author, l_word_count);
   ...
Jasper is proud that he took the time to put this retrieval logic into its own program. Now it can be used in many places in the application. He shows everyone excuse_title at the weekly code review session. Imagine his dismay when Delaware snorts:
Humph. Well, Jasper, it's absolutely peachy keen that you wrote a reusable function. But that is not a program I would ever want to use. The name says you are giving me a title, and you are, but then you are also passing back all that other stuff. It's self-contradictory and I have to declare a bunch of individual variables to use the darned thing!
Jasper pouts; he was so looking forward to a pat or two on the back. Sunita gives Delaware a dirty look and shakes her head. "Jasper," she says, drawing his attention away from Delaware's gloomy outlook, "hiding the lookup was an excellent move. You just need to take a step or two further, and make sure there are no mixed messages. Let's redesign excuse_title together."
Solution: Return multiple values through a single, composite structure or with a procedure.
Here are the steps that Sunita takes to revamp the lookup function and make it more useful:
  • Make sure the name of the program reflects what it does: In this case, the program doesn't return just the title; it returns several pieces of information about an excuse. Let's call it the "excuse_info" function.
  • Pass everything in the RETURN clause: Rather than returning one value through the RETURN clause and another through the parameter list, let's pass everything back in the RETURN clause, using a composite structure—in this case, a record.
Here, then, is the new header of the program:
FUNCTION excuse_info (id_in IN mfe_excuse.id%TYPE)
   RETURN mfe_excuse%ROWTYPE
And here is the revised usage of this function:
PROCEDURE process_excuse (excuse_id_in IN mfe_excuse.isbn%TYPE)
IS
   l_excuse mfe_excuse%ROWTYPE;
BEGIN
   l_excuse := excuse_info (l_id);
Now the code is leaner and cleaner. Everything that is returned by the function is deposited into a single record. And if you are concerned about returning all the data in a table's row, when you need only a small subset of its columns, you can always create your own user-defined record, as shown here:
PACKAGE excuse_pkg
IS
   TYPE key_info IS RECORD (
      title mfe_excuse.title%TYPE
    , author mfe_excuse.author%TYPE
    , word_count mfe_excuse.word_count%TYPE
   );
 
   FUNCTION excuse_info (id_in IN mfe_excuse.id%TYPE)
      RETURN key_info;
END excuse_pkg;
To sum up: the whole point of a function is to return a value (whether it’s a single, scalar value or a composite, such as a record or a collection). If you also return data back through the parameter list with OUT or IN OUT arguments, the purpose and usage of the function will be obscured.
If you need to return multiple pieces of information, take one of the following approaches:
  • Return a record or collection of values 

    Make sure to publish the structure of your record or collection (the TYPE statement) in a package specification so that developers can understand and use the function more easily. 
  • Break up a single function into multiple functions, all returning scalar values

    With this approach, you can call the functions from within SQL statements. 
     
  • Change a function into a procedure

    Unless you need to call a function to return this information, just change it to a procedure returning multiple pieces of information through the OUT arguments in the parameter list
If you follow these guidelines, your subprograms will be more likely to be used and reused, because they will be defined in ways that make them easy to understand and apply in your own code.
 

Search Blog Entries
 
Blog Archives
 
Archive
<May 2013>
SunMonTueWedThuFriSat
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678
Monthly
May, 2013 (15)
April, 2013 (13)
March, 2013 (10)
February, 2013 (5)
January, 2013 (7)
December, 2012 (6)
November, 2012 (10)
October, 2012 (8)
September, 2012 (6)
August, 2012 (8)
July, 2012 (8)
June, 2012 (12)
May, 2012 (21)
April, 2012 (10)
March, 2012 (16)
February, 2012 (19)
January, 2012 (20)
December, 2011 (19)
November, 2011 (14)
October, 2011 (12)
September, 2011 (17)
August, 2011 (15)
July, 2011 (16)
June, 2011 (13)
May, 2011 (15)
April, 2011 (8)
March, 2011 (21)
February, 2011 (17)
January, 2011 (16)
December, 2010 (13)
November, 2010 (13)
October, 2010 (7)
September, 2010 (15)
August, 2010 (11)
July, 2010 (13)
June, 2010 (12)
May, 2010 (14)
April, 2010 (12)
March, 2010 (13)
February, 2010 (12)
January, 2010 (7)
December, 2009 (10)
November, 2009 (12)
October, 2009 (15)
September, 2009 (18)
August, 2009 (13)
July, 2009 (23)
June, 2009 (14)
May, 2009 (17)
April, 2009 (7)
March, 2009 (14)
February, 2009 (7)
January, 2009 (12)
December, 2008 (7)
November, 2008 (11)
October, 2008 (19)
September, 2008 (14)
August, 2008 (11)
July, 2008 (14)
June, 2008 (19)
May, 2008 (12)
April, 2008 (18)
March, 2008 (13)
February, 2008 (8)
January, 2008 (7)
December, 2007 (5)
November, 2007 (8)
October, 2007 (13)
September, 2007 (13)
August, 2007 (16)
July, 2007 (11)
June, 2007 (6)
May, 2007 (5)
April, 2007 (5)
March, 2007 (8)
February, 2007 (6)
January, 2007 (6)
December, 2006 (5)
November, 2006 (8)
October, 2006 (4)
August, 2006 (3)