Hello, you are not logged in.  Login or sign up
Toad on Twitter Follow Toad Search Toad World Search
Blogger List   

All Recent Blog Entries
 

Johannes Ahrends
Unicode and Toad

Ben Boise
Toad SC Discussions

Kevin Dalton
Benchmark Factory

Steven Feuerstein
Oracle PL/SQL

Devin Gallagher
Toad SC discussions

Stuart Hodgins
JProbe Discussions

  Henrik "Mauritz" Johnson
Toad Tips & Tricks on the "other" Toads
  Mark Kurtz
Toad SC discussions
  Michael Lumbard
Toad SC discussions
Daniel Norwood
Toad for Data Analysts,
Toad Extension for Visual Studio
Debbie Peabody
Toad for Data Analysts
Gary Piper
Toad Reports Manager
John Pocknell
Toad for Oracle, JProbe
Kuljit Sangha
Toad SC discussions
Bert Scalzo Indicates Oracle ACE status
Toad for Oracle, Data Modeling, Benchmarking
Jeff Smith
Toad product family
Richard To
SQL Optimization
Jim Wankowski
DB2 - LUW and z/OS
John Weathington
  Toad World Editor
Toad World issues

  Toad Data Modeler Opens in a new window
Data Modeling
 
  Real Automated Code Testing for Oracle
Quest Code Tester blog

Blogs
Toad and Database Commentaries

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.

A Classic Error in My Monthly Puzzle!
 
Location: Blogs Steven Feuerstein's Blog    
 StevenFeuersteinTW Monday, April 27, 2009 8:47 AM

Every month, a Toad World newsletter goes out to thousands of Toad users and it includes a monthly puzzle that I write. Last month's puzzle went like this:

Which of the following blocks does not contain an infinite loop?

A.
DECLARE
   l_line VARCHAR2(32767);
   l_file UTL_FILE.file_type :=
      UTL_FILE.fopen ('C:\temp', 'my_file.txt', 'R');
BEGIN
   LOOP
      UTL_FILE.get_line (l_file, l_line);
   END LOOP;
END;

B.
BEGIN
   LOOP
      DBMS_OUTPUT.PUT_LINE ('abc');
   END LOOP;
END;

C.
DECLARE
   l_keep_going BOOLEAN;
BEGIN
   WHILE (l_keep_going)
   LOOP
      DBMS_OUTPUT.PUT_LINE ('abc');
      l_keep_going := SYSDATE IS NOT NULL;
   END LOOP;
END;

D.
BEGIN
   <<start_of_block>>
   DBMS_OUTPUT.PUT_LINE ('abc');
   GOTO start_of_block;
END;

I told my friends at Toad World that the answer was (A), because  UTL_FILE.GET_LINE raises the NO_DATA_FOUND exception when you read past the end of the file. Since files cannot be of infinite size, you will eventually read to the end of the file and then the loop will terminate.

And I wiped my hands of that puzzle. Unfortunately, it came back to haunt me in the form of a message from the Toad World editor-in-chief:

"Steven, normally I don't worry when I get just a few responses to the puzzler with answers different from what you’ve told us is the correct one, but this month I’m wondering if we missed something because we’ve had close to 50% of the respondents picking the wrong answer (C), and explaining their choice as follows: The value of l_keep_going is not initialized to TRUE and is therefore unknown. It will not enter the loop and therefore the loop is not infinite."

Oh my, oh my. They are so right. And I was so sloppy. And I was so over-confident, that I did not ask anyone with PL/SQL experience to proof my Q&A.

Let's take a closer look at choice C:

DECLARE
   l_keep_going BOOLEAN;
BEGIN
   WHILE (l_keep_going)
   LOOP
      DBMS_OUTPUT.PUT_LINE ('abc');
      l_keep_going := SYSDATE IS NOT NULL;
   END LOOP;
END;

I declare a variable that I will use to determine termination of the loop, but I neglected to provide a non-null default value. As a result, the WHILE condition fails immediately, the loop body never executes even once – and certainly not an infinite number of times!

This kind of bug often manifests in this form as well:

DECLARE
   l_counter PLS_INTEGER;
BEGIN
   LOOP
      do_something;
      l_counter := l_counter + 1;
      EXIT WHEN l_counter = 100;
   END LOOP;
END;

Again, I have failed to initialize my counter (likely it would be set to 1) and in this case the result is an infinite loop.

Hey, that must have been what I meant to use as choice C! Yeah, right.

So the lessons to be learned are:

  1. Anyone can and everyone does make mistakes. Including the self-named PL/SQL Evangelist. 
     
  2. Code review is a critical component of high quality development. All critical code (and what isn't?) should be looked at by another human being before it goes "live."
Permalink |  Trackback
Search Blog Entries
 
Copyright 2010 by Quest Software  | Terms Of Use | Privacy Statement | Contact Us