|
|
 |
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.

 |
 |
|
|
 |
 |
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:
- Anyone can and everyone does make mistakes. Including the self-named PL/SQL Evangelist.
- 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 |
|
 |
 |
|
 |
|
 |
|
|