You can see from the number of iterations that we went through with this one piece ofcode that you can save a lot of time by catching syntax errors as you write code.. I’vefound that the
Trang 11: DECLARE 2: v_MyChar VARCHAR2(20) := ‘test’;
3: v_NUMBER NUMBER;
4: v_Date DATE := SYSDATE;
5: v_counter INTEGER;
6: BEGIN 7: DBMS_OUTPUT.PUT_LINE(‘This is a Test’);
8: DBMS_OUTPUT.PUT_LINE(‘Of Syntax Error Debugging’);
9: For v_COUNTER IN 1 5 LOOP 10: DBMS_OUTPUT.PUT_LINE(‘You are in loop: ‘ 11: || v_counter);
12: END LOOP;
13: END;
14: / This is a Test
Of Syntax Error Debugging You are in loop: 1 You are in loop: 2 You are in loop: 3 You are in loop: 4 You are in loop: 5
PL/SQL procedure successfully completed.
Finally, you get some good results The purpose of this example is to demonstrate thefollowing:
• One syntax error sometimes masks others Fixing that one will bring the others tolight
• The line number that Oracle flags as containing the error might not necessarily bethe location of the true error
• Taking the time to type in your code carefully saves a lot of time during programtesting
You can see from the number of iterations that we went through with this one piece ofcode that you can save a lot of time by catching syntax errors as you write code Thenext section gives you some tips to help you do just that
Preventing Syntax Errors
It would be nice if it were possible to somehow prevent all syntax errors from occurring
Unfortunately, you are a human being, humans do make mistakes, and nothing you dowill ever change that There are, however, some things that you can do to reduce yourchances of ever writing syntax errors into your code
INPUT
OUTPUT
Trang 2One thing you can do is become familiar with the most common types of errors I’vefound that the list of common syntax errors includes
• Using=where:=belongs
• Leaving off the semicolon at the end of a statement
• UsingELSEIFwhenELSIFis correct
• Using double quotes (“) for strings instead of single quotes (‘)Keep these common errors in mind as you write code Also, determine what your person-
al list of common mistakes is, and keep that in mind as well Just the act of being sciously aware of these potential mistakes will lessen the chance that you will make one
con-of them
The following are some other things you can do that you might find helpful:
• Format your code Indent constructs such as loops and IFstatements so that youcan easily follow the logic flow, and so that you can easily spot missing END IFs,
ENDs,LOOPstatements, and so forth
• Double-check expressions containing parentheses immediately after you writethem The number of left parentheses should match the number of right parenthe-ses
• If you are coding an IFstatement, start by writing the IFandENDIFlines Thatway, you know that you have the beginning and ending of the statement writtencorrectly Then back up and insert the needed code between those two lines
• Do the same thing when coding loops as when coding IFstatements Write thebeginning and ending lines first
You can also use an editor that recognizes PL/SQL syntax, or that at least can check formismatched parentheses and quotation marks
One programmer’s editor that I find very helpful in this regard is MultiEdit MultiEdit matches parentheses for you, highlights quoted strings, and bold- faces many SQL and PL/SQL keywords You can find out more about MultiEdit by visiting http://www.multiedit.com
Note
Handling Logic Errors
Unlike syntax errors, logic errors do not stop a program from compiling Logic errors are those that are caused when you misunderstand the problem at hand, or
N EW T ERM
Trang 3when you misunderstand the solution They are mistakes that you make in the logicalflow of a program, not in the syntax of the code that you write After a program is com-piled and tested, logic errors can still occur Possible logic errors include the following:
• Not using proper order of operations
• Using the wrong calculation
• Using loops that never terminateLogic errors are the hardest errors to debug, primarily because the compiler can’t evenbegin to tell you where such an error occurs You are totally on your own when it comes
to finding and fixing logic bugs The main steps in debugging logic errors are to identifythe problem, narrow down the location of the problem, and then fix the problem
The next few sections talk about problems that can occur because the order of operations
is not understood, or because of loops that aren’t coded correctly Following that, you’llfind a section talking about things you can do to help debug logic errors
Order of Operations
Remember when students would ask if there are any real-world applications ofmath? Well, understanding the order of operations is critical, not only in algebra,but in PL/SQL and every programming language, database, and spreadsheet package you
might use The order of operations states the order of precedence each operator is given.
Table 13.1 covers just a few of these levels, with the top level being the highest-priorityorder Day 3, “Writing PL/SQL Expressions” covers this topic in detail
T ABLE 13.1 Simple Order of Operations, from Highest to Lowest
5 + 3 * 9Whenever I ask this question in the classroom, at least one quarter of the class tells methe answer is 72 However, the order of operations tells you that multiplication should
N EW T ERM
Trang 4come first In this case, 3 * 9 = 27, and when you add 5, you get the correct answer, 32.What if you wanted to arrive at 72? You would use parentheses around the expressionyou want to evaluate first:
(5 + 3) * 9 = 72Misunderstanding the order of operations is a very common problem in areas of busi-ness, finance, statistics, and scientific application programming On Day 3, you learned agreat deal about this issue of operator precedence
Nonterminating Loops
Another common logic problem is loops that never terminate As an example, take a look
at the code in Listing 13.2
1: DECLARE 2: v_MyNumber NUMBER := 0;
3: BEGIN 4: LOOP 5: IF v_MyNumber = 7 THEN 6: EXIT;
As you can see, this loop will never exit because v_MyNumberwill never evaluate
to 7 Since it starts at zero, and is incremented by two each time, it will go from
6 to 8 skipping 7 To fix this, you could rewrite line 5 so that it looks like this:
IF v_MyNumber >= 7 THEN
This is a much safer way to terminate a loop, because it doesn’t matter whether the
v_MyNumbervalue is an exact match or not It won’t matter if the increment in line 8 is a
2 or a 3 or a 1 Whenever the value becomes greater than or equal to 7, the loop will minate
ter-Debugging Approaches for Logic Errors
When you find that you have a logic error somewhere in your code, there are severalthings you can do to find it:
INPUT
ANALYSIS
Trang 5• Set up a test environment
• Set up some realistic test data
• Narrow down the scope of the problem until you find itThe first two items are things you should do before you even begin development As forthe third item, finding the exact location of a bug is often easier said than done However,there are some techniques that you can use to better enable yourself to do that The fol-lowing sections describe these three items in more detail
Setting Up a Test Environment
Although testing might seem like common sense, you would not believe how manymajor corporations either don’t have test environments for all their applications or simplyput code into production without thoroughly testing the code in a test environment Thisproblem occurred at one firm that used a program to calculate the raises for employees
The managers would enter a percentage such as 05 Unfortunately, the code took thecurrent pay rate multiplied by the percentage of the raise and assigned this to the newvalue of the hourly rate So people with a 5% raise on $10.00 per hour now were making
50 cents per hour! The formula should have been pay_rate * (1+raise) Imaginebeing the IT manager trying to explain this “glitch” to your coworkers
Unfortunately, this problem is more common than it might seem Another case concernscode that that works fine when initially placed in production, but it affects code in laterproduction processes Whenever possible, you should set up a test environment and testextensively It’s best to have someone else actually do the testing Programmers oftenprefer to test by themselves due to an often unspoken fear that a third party will findmore bugs Well, that’s often true! Take advantage of it
Setting Up Test Data
After you have set up your test environment, you need to test the code with sample data
One method to determine test data is to come up with a spreadsheet with a list of all sible values, or ranges of values, and then manually calculate the output The whole pur-
pos-pose of programming is to work with the inputs, and output the desired results Use test
data that might not be used currently in the system, but that could possibly be entered bythe user, and so on For example, if a program uses only positive numbers, enter a nega-tive number as test data In addition to testing the unusual cases, your test environmentshould also include a reasonable volume of typical production data
Setting up test data and testing all possible outcomes is critical in debugging any tion A major advantage of having a predefined test environment is that it allows you todocument a series of tests and repeat them each time you modify your code Taking a lit-tle extra time to do thorough testing will benefit you greatly down the road
Trang 6applica-Narrowing Down the Location of a Bug
Suppose you encounter a case in which outputs do not match the desired output Whatsteps do you take next? No matter what, you need to narrow down the search area, espe-cially because large-scale applications have millions of lines of code The steps I wouldtake to troubleshoot for a logic error bug are as follows:
1 Determine the overall process
2 Determine where, when, and how frequently the error occurs
3 Determine what outputs are invalid
4 Determine what inputs and calculations make up those outputs
5 Determine what does work (This question can help in determining the cause.)
6 Define the problem
7 Trace inputs, intermediate computations, and outputs
8 Step away from the problem
9 Ask for help Software bugs have been discovered this way!
10 Document the solution
The next few sections talk briefly about each of these steps
Determining the Overall Process
Before you can troubleshoot, you should have some idea of the overall process and how
it relates to the business If you have no reinsurance knowledge, it will make shooting a reinsurance application much more difficult If you have been called in totroubleshoot someone else’s problem, take time to learn the nature of the processesinvolved Often that can help you more quickly focus on the specific module of code that
trouble-is causing the trouble
Determining Where, When, and How Frequently the Error Occurs
You should know where in the system the problem is occurring What forms areinvolved? What data is involved? When does the problem occur and how frequently?Every time a user clicks the Send button? Every time a form is saved and the data isinserted into the table? Only when uniform #23 is inserted into the basketball database?Finding the answers to all these questions will help to determine the root problem
Determining What Outputs Are Invalid
When attempting to define the problem, if it is not a systems crash but an error on put, attempt to define all outputs that are invalid Such questions for a banking industrycould be: Which accounts get a service fee when they are not supposed to? How much is
Trang 7the service fee? (You can use this information to see which variable references this value
in a table.) How often does the error occur? What was the last transaction that occurredbefore the service fee? (Perhaps a trigger is causing the problem when updating thetable.) What date does the error occur? (If the date is fixed, this will help to narrow downthe problem area.) In reality, there should be no random problems, even though the prob-lems might initially seem random You should eventually see a pattern evolve, which willlead you to the problem
Determining What Inputs and Calculations Make Up Those Outputs
If you know a bank fee is accessed, for example, you should begin researching the ules, programs, triggers, procedures, and so on that are involved with processing that fee
mod-What tables do your inputs come from? Knowing the specific program elements involvedcan help you trace the problem more effectively
Determining What Does Work
Asking the question “What does work?” might seem like an odd idea, but believe it ornot, it is very effective If you suspect that a procedure is bad, because the data you pass
to the procedure is not processing properly, check the other modules that access this cedure If they all have the same problem, it is the module If all of them process proper-
pro-ly, and you pass the same number of parameters, maybe it is something in your module
If the range of values you pass is different than that of the other modules accessing theprocedure, it could be an out-of-range error in the procedure
Defining the Problem
Usually, defining the problem is the most difficult part If you have worked your waythrough proper troubleshooting and the asking of questions, you should now be able todetermine the root cause of the problem, and where to start your search to fix the prob-lem Many people try to define the problem first, and take away the symptoms with
“workaround” coding rather than find the true root cause, which could resurface at anytime
Tracing Inputs, Intermediate Computations, and Outputs
To help narrow down a problem to a specific module, and then to specific lines of codewithin that module, you can use the DBMS_OUTPUTpackage to output the values of keyvariables as the code executes You can also write a debugging package—as you’ll seelater in this lesson—to log this information to a text file or a database table Writingdebug output to a file eliminates the problem of having it scroll off the screen too quick-
ly, and also prevents display forms from being overwritten
Trang 8Stepping Away from the Problem
Have you ever had the solution to the problem stare you in the face but you did not seeit? All too often, we get so involved in trying to find and eliminate the bug that we gettoo frustrated and start to repeat steps that we have already eliminated
When faced with a situation like this, it often helps to take a break and get away from theproblem If whatever you’re doing now isn’t working, your whole approach to the prob-lem may be flawed You may need to give your subconscious mind some time to come
up with a fresh approach So instead of working late, beating your head against the wall,and frustrating yourself, go home In the morning, you may find that you’ve thought up afresh approach, or you may even “see” the solution that you missed the night before
Asking for Help
If after you examine the code, it appears that you have followed all punctuation and tax rules, and you have a complete understanding of the function package, procedure,and so on, don’t be afraid to ask another consultant or programmer for help Sometimes
syn-an extra set of eyes csyn-an pinpoint the problem In addition, you might learn some new tipsand tricks to speed up development or troubleshooting the next time around
Documenting the Solution
You should document the solution, on paper, in the program (if possible), and ideally in
an Oracle database of troubleshooting solutions This will help you if the problem reoccurs and you can’t remember what you did to fix it Also, if you do this, you are onyour way to building an expert system that might be of some value to other clients or endusers This is probably one of the most important processes you should complete afteryou have solved the problem If you’re too busy to document right after solving the prob-lem, you might live to regret the decision if a similar error occurs and you have to spendmore time trying to solve the problem again Make the time!
Using Tools to Help in Debugging a Program
Tools can be an invaluable debugging aid, especially if you have access to a source codedebugger Historically, this has not been one of PL/SQL’s strong points Oracle doesn’tsupply a debugger at all for server-level stored procedures and triggers Developer 2000,
a client-side development tool, does include debugging capabilities There are also somethird-party tools on the market, many of which are mentioned on Day 1, “Learning theBasics of PL/SQL.”
A good debugging tool will allow you to step through the execution of a procedure or afunction one line at a time, examining variables as you go This enables you to quicklypinpoint most problems If you don’t have a debugging tool available, there are still a
Trang 9couple things you can do The DBMS_OUTPUTpackage can often be used to good effect
You can use it to display the values of key variables as a procedure executes If you want
to get a bit more involved, you can create a simple debugging package to log debuggingmessages to a disk file
TheDBMS_OUTPUTpackage is described in great detail on Day 17, “Writing to Files andthe Display.” This package will either pass information to a buffer that can be retrieved,
or it can display information to the screen (When debugging a process, if I use
DBMS_OUTPUT, I almost always output to the screen.)The primary use for DBMS_OUTPUTwhen debugging is to display the values of key vari-ables as a procedure or function executes This is a time-honored approach to debugging
The key is to display information that will allow you to narrow down the focus of yoursearch For example, if you display a critical variable before and after a function call, andthe value was correct before the call but incorrect afterward, you should focus yourfuture efforts on the code that you called
If you are using SQL*Plus to compile procedures in the database, you must issue the lowing command in order to see any output:
fol-SET SERVEROUTPUT ON
To disable sending output to the screen, you would turn off SERVEROUTPUT, like this:
SET SERVEROUTPUT OFF
If you use DBMS_OUTPUTas a debugging tool, and you are debugging server code by usingSQL*Plus, don’t forget to turn on SERVEROUTPUT
DBMS_OUTPUTis nice if you are debugging a procedure or function that you can invokefrom SQL*Plus However, if you need to run a client-side program in order to debug theinteraction between that program and the stored procedure, you won’t be able to useSQL*Plus to view the output In such a case, you might want to consider creating a sim-ple debugging package to log debug messages to a file One such implementation isshown in Listings 13.3 and 13.4 This DEBUGpackage allows you to do just two things:
• Take the system date and time, comments, and the contents of a variable, and writethese to a file while the program executes
• Reset the file (erase the file) to start a new debugging run
INPUT
INPUT
Trang 10The statement in Listing 13.3 creates the package header, which defines the proceduresavailable within the package.
1: CREATE OR REPLACE PACKAGE DEBUG AS 2: /* Procedure OUT is used to output a comment of your 3: choice, along with the contents of the variable The 4: Procedure OUT statement defines the format of the function */
5: PROCEDURE OUT(p_Comments IN VARCHAR2, p_Variable IN VARCHAR2);
6:
7: /* Procedure Erase is used to erase the contents of the file.
8: Used to start a new debugging process Good idea to call 9: this function first */
initializa-UTL_FILE package.
Note
1: CREATE OR REPLACE PACKAGE BODY DEBUG AS 2: PROCEDURE OUT(p_Comments IN VARCHAR2,p_Variable IN VARCHAR2) IS 3: v_MyFHOUT UTL_FILE.FILE_TYPE; Declare File Handle 4: BEGIN
5: /* Use A to append all output being sent to the file */
13:
INPUT
Trang 1115: TO_CHAR(SYSDATE,’mm-dd-yy HH:MM:SS AM’) 16: || ‘“,”Comment: ‘ || p_Comments ||
24: WHEN OTHERS THEN 25: DBMS_OUTPUT.PUT_LINE 26: (‘ERROR ‘ || to_char(SQLCODE) || SQLERRM);
27: NULL; Do Nothing 28: END OUT; End Execution of Procedure OUT 29:
30:
31: PROCEDURE Erase IS 32: v_MyFH UTL_FILE.FILE_TYPE; Create File Handle 33: BEGIN
34: /* Open file to overwrite current file contents Doing this 35: erases the contents of the original file completely */
45: DBMS_OUTPUT.PUT_LINE 46: (‘ERROR ‘ || to_char(SQLCODE) || SQLERRM);
47: NULL;
48: END Erase; End Procedure Erase 49:
50: BEGIN 51: Erase; Erase contents of the file 52:
53: END DEBUG; End procedure DEBUG 54:/
Package body created.
You can now examine the components of the newly created DEBUGpackage
TheDEBUG.OUT Procedure
TheDEBUG.OUTprocedure enables you to log debugging messages to a file called
debug.txt The procedure automatically includes the system date and time with each
OUTPUT
Trang 12message The procedure accepts two parameters: a debug message and the variable youare tracking Each time you call it,DEBUG_OUTappends the message and the value of thevariable to the file named debug.txt.
TheDEBUG.ERASE Procedure
TheDEBUG.ERASEprocedure erases the contents of the debug.txtfile by opening a dle to the file in replace mode (‘W’) and then closing the file This process creates anempty file You should make at least one call to DEBUG_ERASEat the start of each debug-ging run to ensure that you start with a clean file
One possible use for the DEBUGpackage is to log the inputs and outputs from a functionthat you are testing Listing 13.5 shows a function representing a variation on Oracle’sbuilt-in ADD_MONTHSfunction This function is named ADD_MON, and includes calls to
DEBUG.OUTto log both the input date and the date that it returns
1: CREATE OR REPLACE FUNCTION add_mon (date_in DATE, 2: months_to_add NUMBER) 3: RETURN DATE AS
4: /*Similar to the built-in ADD_MONTHS, but this function 5: leaves the date alone as much as possible The day is only 6: adjusted if it is out of range for the new month.*/
28: IF day_in = day_work THEN
INPUT
Trang 1334: END IF;
35:
36: Return the new date to the caller.
37: debug.out (‘DATE_OUT = ‘, 38: TO_CHAR(date_out,’yyyy mm dd hh mi ss’));
in the log to verify that the results are what you expect
Listing 13.6 shows a test run being made on the ADD_MONfunction
11: 4 FROM dual;
12:
13: TO_CHAR(ADD 14: - 15: 31-MAR-2000 16:
ANALYSIS
I NPUT /
O UTPUT
continues
Trang 1423: 4 FROM dual;
24:
25: TO_CHAR(ADD 26: - 27: 29-MAR-2000 28:
29: SQL>
30: SQL> SELECT TO_CHAR(
31: 2 ADD_MON(TO_DATE(‘15-FEB-2000’,’DD-MON-YYYY’),1), 32: 3 ‘DD-MON-YYYY’)
33: 4 FROM dual;
34:
35: TO_CHAR(ADD 36: - 37: 15-MAR-2000 38:
39: SQL>
40: SQL> SELECT TO_CHAR(
41: 2 ADD_MON(TO_DATE(‘31-JAN-2000’,’DD-MON-YYYY’),1), 42: 3 ‘DD-MON-YYYY’)
43: 4 FROM dual;
44:
45: TO_CHAR(ADD 46: - 47: 29-FEB-2000
Line 1 contains a crucial call to DEBUG.ERASE This call creates an empty
debug.txtfile for use by subsequent calls to DEBUG.OUT Lines 6–15 demonstratehow the built-in ADD_MONTHSfunction operates Because the input date 29-Febrepresent-
ed the last day of the month, the output date was adjusted so that it also represented thelast day of the month Instead of returning 29-Mar,ADD_MONTHSreturned31-Mar Lines18–27 demonstrate how ADD_MON’s behavior is different ADD_MONadds one month, butpreserves the day, resulting in the value 29-Mar The remaining lines test some othercases that ADD_MONmust handle correctly
Having executed these tests, you’ll find that the debug.txtfile contains these entries:
Trang 15to reduce the amount of code to sort through when a problem occurs, but to be able toreuse those modules in the future.
Defining Requirements and Planning Projects
When you develop a new application, you should spend a significant amount of timedefining the requirements of the users Not only does this require some knowledge of thebusiness, but it should cover all possible input and desired output scenarios Someoneknowledgeable in the industry should verify all calculations What do you gain by sittingwith the end users and verifying the application? You begin to understand the businessand its needs, and you might be able to make suggestions that could aid in decision-making processes, reduce work time for manual processing, improve productivity, and so
on Not only that, it is easier to troubleshoot the system and identify problems before theapplication is placed in production I can’t stress enough how important it is to under-stand and plan for the application in the beginning: Doing so will save you a lot of timeand aggravation at the tail end of the project
Always verify your understanding of the requirements with the business users of the system Tell them what you think you heard them say in the first place Make sure that they agree that you have a correct understanding of the problem at hand.
Trang 16Using a Modular Approach to Coding
When developing your applications, you should take a modular approach to make ging easier This also gives you the added benefit of creating reusable code For instance,
debug-in a payroll application, you could design modules to do the followdebug-ing:
• Calculate gross wage
• Calculate FICA
• Calculate federal withholdings
• Calculate state withholdings
• Withhold for benefits such as flexible spending or insurance
If a problem occurs that is related to gross wages, you can easily narrow down whichprocedure(s) is broken and then fix the bug In addition, modules have another importantaspect: You can test the modules independently of one another
Commenting Code
One of the greatest benefits you can provide for yourself and other Oracle developers is
to liberally comment your code Although you could provide documentation manuals, inpractice these manuals tend to get “misplaced” in almost every environment Addingcomments to your code will help, whether you are trying to debug the application or sim-ply modifying the application to meet new requirements
Proper labeling of variables is also important Poorly worded variables confuse the oper and waste valuable time for people who are trying to follow the logic of the pro-gram Listing 13.7 reflects code that can be very confusing at first glance
1: CREATE OR REPLACE FUNCTION RAISE(
2: p1 INTEGER, 3: p2 NUMBER) 4: RETURN NUMBER IS 5: p3 NUMBER;
6: BEGIN 7: IF p1 = 1 THEN 8: p3 := p2 * 1.10;
9: ELSIF p1 = 2 THEN 10: p3 := p2 * 1.05;
11: ELSIF p1 = 3 THEN 12: p3 := p2 * 1.04;
13: ELSIF p1 = 4 THEN 14: p3 := p2 * 1.03;
15: ELSIF p1 = 5 THEN 16: p3 := p2 ;
INPUT
Trang 1717: ELSE 18: p3 := p2 * 1.02;
19: END IF;
20: RETURN p3; 21: END RAISE;
22: /
A quick glance at this code shows that there are no comments, and that the able names are not mnemonic In order to follow the code, you would have tofirst determine what p1,p2, and p3are You also do not know what the function raises:
vari-An hourly pay rate? The cost of benefits? Someone’s GPA? The elevation of a buildingunder construction?
Raise can mean many things, so a clarification is very important The same code is
pro-vided again in Listing 13.8, with comments that easily clarify the function
1: CREATE OR REPLACE FUNCTION RAISE(
2: p_paylevel INTEGER, parameter for input of raise level 3: p_payrate NUMBER) parameter for input of pay rate 4: /* The purpose of this function is to calculate ANNUAL raises 5: for all of the hourly employees, based upon their raise level 6: values 1-4 and all others */
14: IF p_paylevel = 1 THEN 15: v_newrate := p_payrate * 1.10; Promotion Raise 16: ELSIF p_paylevel = 2 THEN
17: v_newrate := p_payrate * 1.05; Exceeds Rate 18: ELSIF p_paylevel = 3 THEN
19: v_newrate := p_payrate * 1.04; Hi Meets Rate 20: ELSIF p_paylevel = 4 THEN
21: v_newrate := p_payrate * 1.03; Meets Rate 22: ELSIF p_paylevel = 5 THEN
23: v_newrate := p_payrate ; Consultants who get no raise 24: ELSE
25: v_newrate := p_payrate * 1.02; All Others 26: END IF;
27: RETURN v_newrate; Returns new paylevel rate to procedure 28: END RAISE;
29: /
ANALYSIS
INPUT
Trang 18You can now follow the function, its purpose, what the variables are, and anymodifications made at a later date What a difference commenting and propernaming of variables makes!
Writing Assertions into Code
An assertion, in programming terms, is a test for a fact that should be true.
Assertions serve several functions Their primary function is to prevent errorsfrom propagating further downstream in a process Say you had a function that was neversupposed to return a negative value You could actually place a check in your function to
be sure that a negative value is never accidentally returned Listing 13.9 shows oneapproach that you might take to this problem
1: CREATE OR REPLACE FUNCTION do_calc 2: RETURN NUMBER AS
3: return_value NUMBER;
4: BEGIN 5:
6:
7: IF return_value < 0 THEN 8: RAISE_APPLICATION_ERROR ( 9: -20000,’DO_CALC: Negative value returned.’);
A test like the one shown in Listing 13.9 is an assertion Should you make a mistakecoding the DO_CALCfunction, or should some future maintenance programmer induce anerror, the assertion would fire, and you would immediately be alerted to the problem.Assertions also, in a manner of speaking, serve as a form of documentation to futuremaintenance programmers They are like a comment, but with a loaded gun
Coding assertions as shown in Listing 13.9 isn’t too practical You don’t have any centralcontrol over whether they fire, and you can’t make global changes to their behavior Amore robust approach is to create a procedure such as the one shown in listing 13.10
ANALYSIS
N EW T ERM
INPUT
ANALYSIS
Trang 191: CREATE OR REPLACE PROCEDURE ASSERT ( 2: condition IN BOOLEAN,
3: message IN VARCHAR2) AS 4: BEGIN
5: IF NOT condition THEN 6: RAISE_APPLICATION_ERROR (-20000,message);
DO_CALCfunction in Listing 13.9
1: CREATE OR REPLACE FUNCTION do_calc 2: RETURN NUMBER AS
3: return_value NUMBER;
4: BEGIN 5:
for-• For each new block of code, indent two to five spaces
• Use uppercase for keywords
• Use mixed case for variable names
• Precede variable names with a v_for variable,p_for parameters, and so on
• Use one statement per line
INPUT
INPUT
ANALYSIS
ANALYSIS
Trang 20Using Proper Indentation
Every time you start a new block of code, such as a loop, an IFstatement, or a nestedblock, you should indent to make the code more readable Listing 13.12 shows an exam-ple of poorly indented code
1: DECLARE 2: v_MyNumber NUMBER := 0;
3: BEGIN 4: LOOP 5: IF v_MyNumber > 7 THEN 6: EXIT;
If you reformat the code as shown in Listing 13.13, you can follow the program moreeasily
1: DECLARE 2: v_MyNumber NUMBER := 0;
3: BEGIN 4: LOOP 5: IF v_MyNumber > 7 THEN 6: EXIT;
7: v_MyNumber := v_MyNumber + 2;
8: END LOOP;
9: END;
10: /
Not only is the code now easier to read, but the indentation makes it obvious that
anENDIFstatement is missing after line 6
INPUT
ANALYSIS
INPUT
ANALYSIS
Trang 21Using Uppercase for Keywords
Using uppercase for reserved words or functions helps to distinguish between regularcode and Oracle-provided code If a keyword is misspelled, you can easily spot the prob-lem All the listings that you have seen in this book have capitalized SQL and PL/SQLkeywords The code in Listing 13.14 shows how less readable code can become if youdon’t do this
1: declare 2: v_mynumber number := 0;
3: begin 4: loop 5: if v_mynumber > 7 then 6: exit;
dif-Using Mixed Case for Variable Names
To identify code, output, keywords, or variable names, you can easily distinguish able names by using mixed case By using MyVariable, for example, you can pick thevariable name out faster than you could pick out myvariableorMYVARIABLE
By preceding variables with a first letter and an underscore, you can quickly identifyvariables and their type One possible scheme is to use v_for regular variables,p_forparameters, and so forth That way, you know at glance whether you are dealing with aregular variable, a parameter, or another specific kind of variable
Using One Statement per Line
Because the semicolon (;) is used to terminate a statement, you could easily have ple statements on one line For instance, you could code something like this:
multi-y := ‘’; x :=1;
LOOP x := x+1; y := y+’ ‘; if x=10 THEN EXIT; END IF; END LOOP;
INPUT
ANALYSIS
Trang 22Although this code is syntactically correct and will execute, you’ll run into trouble if youtry to troubleshoot it or comment out a statement that might be causing the error Thecode would be much easier to follow if you formatted it like this:
Q What can I use to debug applications?
A UsingDBMS_OUTPUTto display the values of key variables is one method of ging You can also create your own debugging package to log debugging messages
debug-to a file
Trang 23Q If all operations are on the same level, how does Oracle know which tions to process first?
calcula-A If all calculations are at the same level, the order of evaluation is from left to right.
Q What simple punctuation can easily override the natural order of operations?
A Parentheses () Operations in parentheses are evaluated first, and the results areused in the rest of the expression
Q Are comments needed in an application if you have sufficient separate documentation?
A Yes, absolutely Documentation tends to get misplaced or never gets updated when
a coding change is made You should document not only what each procedure,function, and trigger does, but also document changes and updates as they occur
Q Must we really document solutions to problems?
A Documenting solutions to problems helps you troubleshoot similar problems that
occur in the future
Q Why does proper formatting help in debugging code?
A Proper formatting allows you to view code quickly and assess what the code is
doing If you do not line up END IFstatements when you are nesting IF THEN
clauses, it is difficult to see when the first statement ends, the second ends, and soforth
1 True or False: Logic errors are easier to debug than syntax errors
2 Missing a semicolon is what type of an error?
3 Provide the answer to the calculation 6 + 4 / 2 = ?
4 True or False: Commenting code is a waste of time
5 True or False: Formatting code is not necessary
Trang 24TheDEBUGpackage in this lesson always writes debugging messages to the file named
debug.txt That will cause problems if multiple developers use the package at once.Modify the DEBUGpackage as follows:
• Modify the ERASEprocedure to accept a filename This filename will be used bysubsequent calls to the OUTprocedure
• Modify both the OUTandERASEprocedures so that if no filename is passed, or if
ERASEis never called, no file is created and no messages get written
For extra credit, add an ASSERTprocedure to the DEBUGpackage, and build in a flag sothat you can enable and disable assertions at will
Trang 25les-DBMS_LOBpackage Today’s lesson focuses on the following topics:
• Defining large objects
• Using the DBMS_LOBpackage with external files
• Understanding locators
• Using the DBMS_LOBpackage with internal files