Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
2,63 MB
Nội dung
Debugging Your Code and Preventing Errors 377 13 1: 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 the following: • One syntax error sometimes masks others. Fixing that one will bring the others to light. • The line number that Oracle flags as containing the error might not necessarily be the location of the true error. •Taking the time to type in your code carefully saves a lot of time during program testing. You can see from the number of iterations that we went through with this one piece of code that you can save a lot of time by catching syntax errors as you write code. The next 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 do will ever change that. There are, however, some things that you can do to reduce your chances of ever writing syntax errors into your code. I NPUT O UTPUT 17 7982 ch13 11/30/99 1:10 PM Page 377 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. One thing you can do is become familiar with the most common types of errors. I’ve found that the list of common syntax errors includes •Using = where := belongs • Leaving off the semicolon at the end of a statement •Using ELSEIF when ELSIF is 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 con- sciously aware of these potential mistakes will lessen the chance that you will make one 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 IF statements so that you can easily follow the logic flow, and so that you can easily spot missing END IF s, END s, LOOP statements, and so forth. • Double-check expressions containing parentheses immediately after you write them. The number of left parentheses should match the number of right parenthe- ses. • If you are coding an IF statement, start by writing the IF and ENDIF lines. That way, you know that you have the beginning and ending of the statement written correctly. Then back up and insert the needed code between those two lines. • Do the same thing when coding loops as when coding IF statements. Write the beginning and ending lines first. You can also use an editor that recognizes PL/SQL syntax, or that at least can check for mismatched parentheses and quotation marks. 378 Day 13 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 17 7982 ch13 11/30/99 1:10 PM Page 378 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. Debugging Your Code and Preventing Errors 379 13 when you misunderstand the solution. They are mistakes that you make in the logical flow 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 terminate Logic errors are the hardest errors to debug, primarily because the compiler can’t even begin 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 identify the 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’ll find 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 of math? Well, understanding the order of operations is critical, not only in algebra, but inPL/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-priority order. Day 3, “Writing PL/SQL Expressions” covers this topic in detail. T ABLE 13.1 Simple Order of Operations, from Highest to Lowest Operator Description () Parentheses * , / Multiplication, division + , - Addition, subtraction If two or more operators are on the same priority level, then the expression is evaluated from left to right. Take the following equation, which looks as if it should add two num- bers and multiply 9 by the result: 5 + 3 * 9 Whenever I ask this question in the classroom, at least one quarter of the class tells me the answer is 72. However, the order of operations tells you that multiplication should N EW T ERM 17 7982 ch13 11/30/99 1:10 PM Page 379 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. come 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 expression you want to evaluate first: (5 + 3) * 9 = 72 Misunderstanding 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 a great 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. L ISTING 13.2 An Example of an Infinite Loop 1: DECLARE 2: v_MyNumber NUMBER := 0; 3: BEGIN 4: LOOP 5: IF v_MyNumber = 7 THEN 6: EXIT; 7: END IF; 8: v_MyNumber := v_MyNumber + 2; 9: END LOOP; 10: END; 11: / As you can see, this loop will never exit because v_MyNumber will 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_MyNumber value 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 ter- minate. Debugging Approaches for Logic Errors When you find that you have a logic error somewhere in your code, there are several things you can do to find it: 380 Day 13 I NPUT A NALYSIS 17 7982 ch13 11/30/99 1:10 PM Page 380 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. Debugging Your Code and Preventing Errors 381 13 • Set up a test environment • Set up some realistic test data • Narrow down the scope of the problem until you find it The first two items are things you should do before you even begin development. As for the 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 many major corporations either don’t have test environments for all their applications or simply put code into production without thoroughly testing the code in a test environment. This problem 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 the current pay rate multiplied by the percentage of the raise and assigned this to the new value 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) . Imagine being the IT manager trying to explain this “glitch” to your coworkers. Unfortunately, this problem is more common than it might seem. Another case concerns code that that works fine when initially placed in production, but it affects code in later production processes. Whenever possible, you should set up a test environment and test extensively. It’s best to have someone else actually do the testing. Programmers often prefer to test by themselves due to an often unspoken fear that a third party will find more 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 pos- sible values, or ranges of values, and then manually calculate the output. The whole pur- 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 by the 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 environment should also include a reasonable volume of typical production data. Setting up test data and testing all possible outcomes is critical in debugging any applica- tion. A major advantage of having a predefined test environment is that it allows you to document 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. 17 7982 ch13 11/30/99 1:10 PM Page 381 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. Narrowing Down the Location of a Bug Suppose you encounter a case in which outputs do not match the desired output. What steps 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 would take 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 trouble- shooting a reinsurance application much more difficult. If you have been called in to troubleshoot someone else’s problem, take time to learn the nature of the processes involved. Often that can help you more quickly focus on the specific module of code that 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 are involved? 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 is inserted 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 out- put, attempt to define all outputs that are invalid. Such questions for a banking industry could be: Which accounts get a service fee when they are not supposed to? How much is 382 Day 13 17 7982 ch13 11/30/99 1:10 PM Page 382 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. Debugging Your Code and Preventing Errors 383 13 the 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 occurred before the service fee? (Perhaps a trigger is causing the problem when updating the table.) What date does the error occur? (If the date is fixed, this will help to narrow down the 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 will lead 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 mod- ules, programs, triggers, procedures, and so on that are involved with processing that fee. What tables do your inputs come from? Knowing the specific program elements involved can 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 or not, 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 pro- cedure. If they all have the same problem, it is the module. If all of them process proper- 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 the procedure, 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 way through proper troubleshooting and the asking of questions, you should now be able to determine 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 any time. Tracing Inputs, Intermediate Computations, and Outputs To help narrow down a problem to a specific module, and then to specific lines of code within that module, you can use the DBMS_OUTPUT package to output the values of key variables as the code executes. You can also write a debugging package—as you’ll see later in this lesson—to log this information to a text file or a database table. Writing debug 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. 17 7982 ch13 11/30/99 1:10 PM Page 383 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. Stepping Away from the Problem Have you ever had the solution to the problem stare you in the face but you did not see it? All too often, we get so involved in trying to find and eliminate the bug that we get too 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 the problem. 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 a fresh 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 syn- 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 an extra set of eyes can pinpoint the problem. In addition, you might learn some new tips and 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 on your way to building an expert system that might be of some value to other clients or end users. This is probably one of the most important processes you should complete after you 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 spend more 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 code debugger. Historically, this has not been one of PL/SQL’s strong points. Oracle doesn’t supply 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 some third-party tools on the market, many of which are mentioned on Day 1, “Learning the Basics of PL/SQL.” A good debugging tool will allow you to step through the execution of a procedure or a function one line at a time, examining variables as you go. This enables you to quickly pinpoint most problems. If you don’t have a debugging tool available, there are still a 384 Day 13 17 7982 ch13 11/30/99 1:10 PM Page 384 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. Debugging Your Code and Preventing Errors 385 13 couple things you can do. The DBMS_OUTPUT package 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 debugging messages to a disk file. Using DBMS_OUTPUT as a Debugging Tool The DBMS_OUTPUT package is described in great detail on Day 17, “Writing to Files and the 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_OUTPUT when 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 your search. For example, if you display a critical variable before and after a function call, and the value was correct before the call but incorrect afterward, you should focus your future efforts on the code that you called. If you are using SQL*Plus to compile procedures in the database, you must issue the fol- lowing command in order to see any output: SET SERVEROUTPUT ON To disable sending output to the screen, you would turn off SERVEROUTPUT , like this: SET SERVEROUTPUT OFF If you use DBMS_OUTPUT as a debugging tool, and you are debugging server code by using SQL*Plus, don’t forget to turn on SERVEROUTPUT . Writing a DEBUG Package DBMS_OUTPUT is nice if you are debugging a procedure or function that you can invoke from SQL*Plus. However, if you need to run a client-side program in order to debug the interaction between that program and the stored procedure, you won’t be able to use SQL*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 is shown in Listings 13.3 and 13.4. This DEBUG package allows you to do just two things: •Take the system date and time, comments, and the contents of a variable, and write these to a file while the program executes. • Reset the file (erase the file) to start a new debugging run. I NPUT I NPUT 17 7982 ch13 11/30/99 1:10 PM Page 385 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. The statement in Listing 13.3 creates the package header, which defines the procedures available within the package. L ISTING 13.3 Defining the DEBUG Package Components 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. */ 10: PROCEDURE Erase; 11: END DEBUG; -- End Definition of package DEBUG 12: / Package Created After creating the package header, you can now enter and execute the package body as shown in Listing 13.4. 386 Day 13 I NPUT O UTPUT This version of the package body assumes that the UTL_FILE_DIR initializa- tion parameter is pointing to a directory named c:\a . The directory used for the debug.txt file must be one that UTL_FILE_D IR points to. You need to adjust the directory name in this procedure to match the UTL_FILE_DIR set- ting in your environment. See Day 17 for more information on using the UTL_FILE package. Note L ISTING 13.4 Creating the DEBUG Package Components 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 */ 6: 7: v_MyFHOUT := UTL_FILE.FOPEN(‘c:\a’,’debug.txt’,’a’); 8: 9: /* Display System Time and Date as MM-DD-YY HH:MM:SS 10: followed by comments and the contents of the 11: variables. Each element is surrounded by quotation marks and 12: separated by a comma to create a comma separated value file */ 13: 14: UTL_FILE.PUT_LINE(v_MyFHOUT,’”’|| I NPUT 17 7982 ch13 11/30/99 1:10 PM Page 386 Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. [...]... hard drive space The following syntax box demonstrates the COMPARE function FUNCTION COMPARE( Lob1 IN BFILE, Lob2 IN BFILE, Number_Bytes_to_Compare IN INTEGER, Origin_Lob1 IN INTEGER := 1, Origin_Lob2 IN INTEGER := 1) RETURN Compare_Result_Integer; In this syntax the parameters are as follows: Lob1 is the first LOB you are comparing • Lob2 is the second LOB you are comparing • , • Number_Bytes_to_Compare... not have the appropriate privileges to access the file The INSTR Function , SYNTAX The INSTR function allows you to match a pattern against the nth occurrence in the LOB, starting from the offset specified FUNCTION INSTR(BFILE_Locator, Pattern IN RAW, Starting Location IN INTEGER := 1, Nth_Occurrence IN INTEGER := 1) RETURN Status_Integer; In this syntax the parameters are as follows: , • BFILE_Locator... successful Exploring BFILE Examples, Using the DBMS_LOB Package You can test all these functions and procedures with an anonymous PL/SQL block in the next several examples in this section The functions and procedures common to internal and external LOBs, such as INSTR and SUBSTR, are demonstrated later in this lesson, in the section “Exploring Internal LOB Examples, Using the DBMS_LOB Package.” Accessing BFILEs... application in the beginning: Doing so will save you a lot of time and aggravation at the tail end of the project Tip 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 13 There is one pitfall in obtaining user requirements,... modules in the future Defining Requirements and Planning Projects When you develop a new application, you should spend a significant amount of time defining the requirements of the users Not only does this require some knowledge of the business, but it should cover all possible input and desired output scenarios Someone knowledgeable in the industry should verify all calculations What do you gain by sitting... 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 IF statements when you are nesting IF THEN clauses, it is difficult... data item The Internal LOBs can also be either temporary in duration or more persistent in nature: persistent in that the LOB is present during the entire session duration Limitations of LOBs Although they sound invincible, LOBs do have some limitations, such as the following: • LOBs cannot be used in advanced Oracle table storage techniques such as cluster- ing • LOBs are not allowed in GROUP BY, ORDER... be used in a SELECT list of a subquery in an INSERT statement The syntax for the TO_LOB function can be seen in the following example TO_LOB (long value) In this syntax long datatype value is the value of the data item you wish to convert to a LOB The following example illustrates the use of the TO_LOB function: INPUT INSERT INTO lob_table SELECT n, TO_LOB(long_col) FROM long_table; ANALYSIS In this... processing Common problem areas that cause logic errors are improper order of operations when performing calculations and infinite loops Oracle does not feature any built -in debugging package, at least not with the database, although Developer 2000 includes a debugger Proper commenting and formatting of code enables you to review and understand code much faster than you could otherwise Q&A Q What debugging... PM”,”Comment: DATE _IN = “,”2000 02 29 12 00 00” DATE_OUT = “,”2000 03 29 12 00 00” DATE _IN = “,”2000 02 15 12 00 00” DATE_OUT = “,”2000 03 15 12 00 00” DATE _IN = “,”2000 01 31 12 00 00” DATE_OUT = “,”2000 02 29 12 00 00” These entries allow you to verify that the ADD_MON function is operating as expected Debugging Your Code and Preventing Errors 391 Preventing Errors and Planning for Debugging in the Future . and insert the needed code between those two lines. • Do the same thing when coding loops as when coding IF statements. Write the beginning and ending lines. 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