1. Trang chủ
  2. » Công Nghệ Thông Tin

Oracle PL/SQL Language Pocket Reference- P5

50 381 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Exception Handling
Trường học O'Reilly & Associates
Chuyên ngành Oracle PL/SQL
Thể loại book
Năm xuất bản 2000
Thành phố Sebastopol
Định dạng
Số trang 50
Dung lượng 202,35 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Previous: 7.7 Tips for PL/ SQL Loops Oracle PL/SQL Programming, 2nd Edition Next: 8.2 The Exception Section 7.7 Tips for PL/SQL Loops Book Index 8.2 The Exception Section The Oracle Libr

Trang 1

the Oracle7 architecture allows you to embed many of your business rules directly into your database structure, using database triggers, constraints, and stored procedures In many cases, you will want to let the RDBMS trap and reject invalid database actions To do this, you need a way to identify

application-specific errors and return information about those error back to the client This kind of error communication is illustrated in Figure 8.2

Figure 8.2: Error communication from server to client

I have called this type of exception "unnamed" and "programmer-defined." The programmer-defined aspect should be clear: because the error is application-specific, you cannot expect PL/SQL to have already defined it for you The reason this type of exception is also unnamed is that you cannot name

or declare an exception within a server-based program or database trigger and have the client-side tool handle that named exception This identifier simply doesn't cross the great divide between client and server

To get around this problem, Oracle provides a special procedure to allow communication of an

unnamed, yet programmer-defined, server-side exception: RAISE_APPLICATION_ERROR (The use of this procedure and exception type is discussed in Section 8.7, "Client-Server Error

Communication" later in this chapter.) The specification for this procedure is as follows:

PROCEDURE RAISE_APPLICATION_ERROR

(error_number_in IN NUMBER, error_msg_in IN VARCHAR2);

where error_number_in is the error number you have assigned to this error The error_msg_in

argument is the message that will be sent back with the error code to the client program

Previous: 8.2 The

Exception Section

Oracle PL/SQL Programming, 2nd Edition

Next: 8.4 Determining Exception-Handling Behavior

Trang 2

8.2 The Exception Section Book Index 8.4 Determining

Trang 3

Previous: 8.1 Why

Exception Handling?

Chapter 8Exception Handlers

Next: 8.3 Types of Exceptions

8.2 The Exception Section

A PL/SQL block (of which procedures, functions, and anonymous blocks are all instances) consists

of up to four parts: the header, declaration section, execution section, and exception section, as shown

in the following anonymous block:

Trang 4

The WHEN OTHERS clause is optional; if it is not present, then any unhandled exception is

immediately raised in the enclosing block, if any

If the exception is not handled by any PL/SQL block, then the error number and message are

presented directly to the user of the application The exception is, in other words, unhandled and it disrupts the execution of the application

Previous: 8.1 Why

Exception Handling?

Oracle PL/SQL Programming, 2nd Edition

Next: 8.3 Types of Exceptions

8.1 Why Exception Handling? Book Index 8.3 Types of Exceptions

The Oracle Library

Navigation

Copyright (c) 2000 O'Reilly & Associates All rights reserved

Trang 5

Previous: 7.7 Tips for PL/

Why Exception Handling?

The Exception Section

Types of Exceptions

Determining Exception-Handling Behavior

Raising an Exception

Handling Exceptions

Client-Server Error Communication

NO_DATA_FOUND: Multipurpose Exception

Exception Handler as IF Statement

RAISE Nothing but Exceptions

In the PL/SQL language, errors of any kind are treated as exceptions situations that should not occur in your program An exception can be one of the following:

● An error generated by the system (such as "out of memory" or "duplicate value in index")

● An error caused by a user action

● A warning issued by the application to the user

PL/SQL traps and responds to errors using an architecture of exception handlers The

exception-handler mechanism allows you to cleanly separate your error processing code from your executable statements It also provides an event-driven model, as opposed to a linear code model, for processing errors In other words, no matter how a particular exception is raised, it is handled by the same

exception handler in the exception section

When an error occurs in PL/SQL, whether a system error or an application error, an exception is raised The processing in the current PL/SQL block's execution section halts and control is transferred

to the separate exception section of your program, if one exists, to handle the exception You cannot return to that block after you finish handling the exception Instead, control is passed to the enclosing block, if any

Trang 6

Figure 8.1 illustrates how control is transferred to the exception section when an exception is raised

Figure 8.1: Exception handling architecture

8.1 Why Exception Handling?

It is a sad fact of life that most programmers never take the time to properly bullet-proof their

programs Instead, wishful thinking often reigns Most of us find it hard enough and more than enough work to simply write the code that implements the positive aspects of an application: maintaining customers, generating invoices, etc It is devilishly difficult from both a psychological standpoint and a resources perspective to focus on the negative side of our life: what happens when the user presses the wrong key? If the database is unavailable, what should I do?

As a result, we write applications that often assume the best of all possible worlds, hoping that our programs are bug-free, that users will enter only the correct data in only the correct fashion, and that all systems (hardware and software) will always be a "go."

Of course, harsh reality dictates that no matter how hard you try, there will always be one more bug

in your application And your users will always find just the right sequence of keystrokes it takes to make a screen implode The situation is clear: either you spend the time up front to properly debug and bulletproof your programs, or you will fight an unending series of rear-guard battles, taking frantic calls from your users and putting out the fires

You know what you should do Fortunately, PL/SQL offers a powerful and flexible way to trap and handle errors in your programs It is entirely feasible within the PL/SQL language to build an

application which fully protects the user and the database from errors

Trang 7

The exception handler model offers the following advantages:

Event-driven handling of errors As we've mentioned, PL/SQL exception handling follows an

event-driven rather than a linear code model No matter how a particular exception is raised, it

is handled by the same exception handler in the exception section You do not have to check repeatedly for a condition in your code, but instead can insert an exception for that condition once in the exception section and be certain that it will be handled throughout that block (and all of its enclosing blocks)

Clean separation of error-processing code With the exception-handling model, whenever an

exception is raised, program control transfers completely out of the normal execution

sequence and into the exception section Instead of placing error-handling logic throughout different sections of your program, you can consolidate all of this logic into a single, separate section Furthermore, if you need to add new exceptions in your program (perhaps you

overlooked a possible problem, or a new kind of system error has been identified), you do not have to figure out where in your executable code to put the error-handling logic Simply add another exception handler at the bottom of the block

Improved reliability of error handling It is quite difficult for errors to go undetected with the

PL/SQL error-handling model If there is a handler, then that exception will be dealt with in the current block or in an enclosing block Even if there is no explicit handler for that error, normal code execution will still stop Your program cannot simply "work through" an error unless you explicitly organize your code to allow this

There is no avoiding the fact that if you want to trap errors in your PL/SQL programs you will have

to write some additional code The exception handler architecture, however, minimizes the amount of code you will need to write, and offers the possibility of guarding against all problems that might arise in your application The following sections look at how you define, raise, and handle exceptions

in PL/SQL

Previous: 7.7 Tips for PL/

SQL Loops

Oracle PL/SQL Programming, 2nd Edition

Next: 8.2 The Exception Section

7.7 Tips for PL/SQL Loops Book Index 8.2 The Exception Section

The Oracle Library

Navigation

Copyright (c) 2000 O'Reilly & Associates All rights reserved

Trang 8

Previous: 7.6 Managing

Loop Execution

Chapter 7Loops

Next: 8 Exception Handlers

7.7 Tips for PL/SQL Loops

Loops are very powerful and useful constructs, but they are among the most complicated control structures in PL/SQL The tips in this section will help you select the most efficient and easily

maintained loops for your programs

7.7.1 Naming Loop Indexes

How would you like to try to understand much less maintain code that looks like this?

FOR i IN start_id end_id

FOR focus_account IN start_id end_id

Trang 9

meant that "k" represented the hours in a day

Now that I have provided descriptive names for those index variables, however, you discover that the innermost loop actually spanned two sets of twelve months (12 × 2 = 24) Your deduction about "k", while reasonable, was wrong, but it would have been completely impossible to determine this without looking at the build_schedule code Given PL/SQL's ability to hide information within packages, this code might not even be available

Software programmers should not have to make Sherlock Holmes-like deductions about the meaning

of the start and end range values of the innermost FOR loops in order to understand their purpose Use names that self-document the purposes of variables and loops That way other people will

understand your code and you will remember what your own code does when you review it three months later

7.7.2 The Proper Way to Say Goodbye

No matter what kind of loop you are using, there is always only one entry point into the loop: the first executable statement following the LOOP keyword Your loops should also have just one way of leaving the loop The method of exit, furthermore, should be compatible with the type of loop you use The following tips will help you write well-structured and easily maintained loops

7.7.2.1 Premature FOR loop termination

The syntax of the FOR loop states your intent explicitly and should only be a FOR loop if you know

in advance how many times the loop needs to execute For example, the following loop is very clear:

FOR month_count IN 1 12

LOOP

analyze_month (month_count);

Trang 10

END LOOP;

It states: "I am going to execute the analyze_month procedure 12 times, once for each month in the year." Straightforward and easy to understand

Now take a look at the next numeric FOR loop:

FOR year_count IN 1 years_displayed

This approach is very unstructured and contradictory The loop boundary states one thing, but the loop body executes something very different

You should always let a FOR loop (whether numeric or cursor) complete its stated number of

iterations If you do need to conditionally halt loop execution, you should choose either an infinite or

a WHILE loop The above FOR loop could, for example, be easily recoded as follows:

FOR year_count IN 1 LEAST (years_displayed, 11)

LOOP

analyze_month (month_count);

END LOOP;

Similar guidelines apply to the infinite and WHILE loop, as I explore in the next sections

7.7.2.2 EXIT and EXIT WHEN statements

Neither the FOR loop nor the WHILE loop should use the EXIT and EXIT WHEN statements You have already seen why this is so in FOR loops Consider the following WHILE loop:

Trang 11

In this case, even though my loop boundary indicates that the body should execute until

more_records evaluates to FALSE, the EXIT WHEN in the loop body bypasses that condition

Instead of using EXITs in your WHILE loop, you should always rely exclusively on your loop

condition to determine whether the looping should continue The previous WHILE loop can be redesigned as follows:

The author of this program was in a big hurry to return to the calling program!

Once again, if the loop should be conditionally terminated, do not use a FOR loop Instead, use a WHILE or infinite loop and then issue the RETURN after the loop is completed The following code replaces the unstructured IF statement shown above:

Trang 12

/* Initialize the loop boundary variables */

row_index := 0;

the_rowcount := Get_Group_Row_Count (rg_id);

/* Use a WHILE loop */

WHILE row_index <= the_rowcount AND

7.7.2.4 GOTO statements inside a loop

The same reasons for avoiding a RETURN apply to the GOTO statement If you use a GOTO to exit from a loop, you bypass the logical structure of the loop You end up with code that is very difficult

to trace, debug, fix, and maintain

7.7.3 Avoiding the Phony Loop

As I have stated previously, you should not use a numeric FOR loop if you cannot specify in a range scheme of lowest and highest bounds the number of times the loop must execute Just because you know the number of iterations of some code, however, doesn't mean that you should use a loop

I have run across a number of programs which execute variations on this kind of FOR loop:

Trang 13

This loop provides hefty bonuses to the president and CEO of a company that just went deep into debt to acquire a competitor I need to use the loop so the code executes twice to make sure both the president and CEO receive their just compensation Right? Wrong This code should not be inside a loop It does not need iteration to perform its job; the LOOP syntax just confuses the issue

The two sections within the IF-THEN-ELSE construct in the previous example both need to be

executed all the time; this is straight sequential code and should be written as follows:

give_bonus (president_id, 2000000);

give_bonus (ceo_id, 5000000);

7.7.4 PL/SQL Loops Versus SQL Processing

One of the indicators that a numeric FOR loop is being used incorrectly is that the loop index is not used for anything but traffic control inside the loop The actual body of executable statements

completely ignores the loop index When that is the case, there is a good chance that you don't need the loop at all

When should you use standard SQL to accomplish your task and when should you rely on PL/SQL loops? Sometimes the choice is clear: if you do not need to interact with the database, then there is clearly no need for SQL In addition, SQL can't always provide the necessary flexibility to get the job done Conversely, if you are performing a single record insert into a table then there is no need for a loop Often, however, the choice is less obvious For example, a SELECT statement queries one or more rows from the database A cursor FOR loop also queries rows from the database based on a SELECT statement In fact, PL/SQL and native SQL often can both accomplish the task at hand Given that fact, you will need to choose your implementation according to more subtle issues like performance and maintainability of code

Before we look at some examples of scenarios which call for one or the other approach, let's review the difference between the implicit looping of the SQL set-at-a-time approach and the PL/SQL loop

SQL statements such as SELECT, UPDATE, INSERT, and DELETE work on a set of data That set (actually, a collection of rows from a table or tables) is determined by the WHERE clause (or lack thereof) in the SQL statement SQL derives much of its power and effectiveness as a database

language from this set-at-a-time processing approach There is, however, a drawback, as I mentioned earlier: SQL often does not give you the flexibility you might need to handle individual records and specialized logic which must be applied differently to different records

The PL/SQL cursor offers the ability to access a record at a time and to take action based on the contents of that specific record It is not always clear, however, which language component would best fit the needs of the moment I have seen a number of programs where developers went overboard

in their drive to PL/SQL-ize the SQL access to their data This happens most frequently when using a cursor FOR loop

Trang 14

The PL/SQL block in the code below moves checked-out pets from the pet hotel occupancy table to the pets_history table using a cursor FOR loop For each record fetched (implicitly) from the cursor (representing a pet who has hit the road), the body of the loop first inserts a record into the

pet_history table and then deletes the record from the occupancy table:

WHERE checkout_date IS NOT NULL;

DELETE FROM occupancy WHERE checkout_date IS NOT NULL;

Here, a single insert (making use of the INSERT SELECT syntax) and a single delete (which now checks for the checkout_date and not the employee_id) accomplish the transfer of the data to the history table This reliance on native SQL, without the help of PL/SQL, allows you to take full

advantage of array processing It significantly reduces network traffic in a client-server environment because only two SQL statements (instead of 40) are passed to the RDBMS

The cursor FOR loop was not really needed here; the body of the loop did not perform any procedural logic which could not be handled by SQL itself If, on the other hand, the program needed to

selectively reject records for the transfer, or otherwise perform procedural logic not possible within SQL, then either the cursor FOR loop or a WHILE loop would make sense

Trang 15

Previous: 7.6 Managing

Loop Execution

Oracle PL/SQL Programming, 2nd Edition

Next: 8 Exception Handlers7.6 Managing Loop Execution Book Index 8 Exception Handlers

The Oracle Library

Navigation

Copyright (c) 2000 O'Reilly & Associates All rights reserved

Trang 16

Previous: 7.5 The WHILE

Loop

Chapter 7Loops

Next: 7.7 Tips for PL/SQL Loops

7.6 Managing Loop Execution

I've explained how to construct the different kinds of PL/SQL loops The topics in this section

address the following nuances of loop execution:

Trang 17

The label can also appear optionally after the END LOOP reserved words, as the following example demonstrates:

END LOOP month_loop;

END LOOP year_loop;

By providing a label for a loop, you give that loop a name This allows you to use dot notation to refer to loop-related variables, such as the FOR loop index In the following example of nested FOR loops, I qualify my reference to the year_number index with the loop name:

END LOOP month_loop;

END LOOP year_loop;

7.6.1.1 Benefits of loop labels

The loop label is useful in two particular situations:

● When you have written a loop whose code length exceeds a single page, use a loop label to tie the end of the loop back explicitly to its start This visual tag will make it easier for a

developer to maintain and debug the program Without the loop label, it can be very difficult

to keep track of which LOOP goes with which END LOOP

● When you have nested loops, you can use the label to both improve readability and increase control over the execution of your loops This capability is explored in the next section

Trang 18

7.6.1.2 Loop termination using labels

You can affect loop execution by adding a loop label after the EXIT keyword in the EXIT statement

of a loop, as follows:

EXIT loop_label;

EXIT loop_label WHEN condition;

When you specify a loop label with the EXIT statement, PL/SQL terminates the specified loop

Consider the last example with nested year and month loops You might encounter a condition in which both loops should be immediately terminated The usual, unlabeled EXIT statement inside the month loop would simply halt the month processing for the current year The year loop would,

however, continue its iterations If the EXIT statement includes the year_loop label, both loops will halt execution:

EXIT year_loop WHEN termination_condition;

END LOOP month_loop;

END LOOP year_loop;

In this way, the loop labels offer you added control Nevertheless, don't use this variation of the EXIT WHEN statement unless absolutely necessary This kind of EXIT is very unstructured, which makes

it hard to test, debug, and maintain If your loops do have exception conditions, you should instead code them into the boundary of the loop or allow the exception section to handle them

In other words, if you need to conditionally terminate your loop, then you should not use a FOR loop

7.6.2 Loop Scope

A PL/SQL block establishes a scope for all locally-declared variables Outside of the block, those

Trang 19

variables do not exist A similar kind of scope is created in the body of a loop

7.6.2.1 Scope in FOR loops

In both numeric and cursor FOR loops, the scope of the loop index is restricted to the body of the loop You cannot make reference to this implicitly declared variable in code before or after the loop

If you declare a variable of the same name as the loop index, PL/SQL considers that to be a different variable It will not be used within the loop

The loop index always takes precedence over a variable of the same name declared outside the scope

of the loop Suppose you have the following code:

PROCEDURE calc_revenue (year_in IN NUMBER)

If you insist on declaring a variable whose name is the same as that of a loop index, you can use dot notation to qualify your references to these variables In the following example I have a duplicate use

of the month_number identifier:

PROCEDURE calc_revenue (year_in IN NUMBER)

Trang 20

(calc_revenue.month_number) As a result, the compiler can obtain the right value for that

month_number (6), while also using the loop index value in the call to calc_rev_for_month

Of course, you can and should avoid this kind of confusion by using distinct names for your variables and loop indexes

7.6.2.2 Scope with labels

If you define a label for a loop, then this label can be used to qualify the name of identifiers (loop indexes and locally-declared variables) inside the loop

Once the loop has terminated, you cannot use the loop label to qualify identifiers The scope of that label, in other words, is the boundary and body of the loop

In the following example, I created two nested loops, both of which use a loop index named

date_number (Warning! Do not try this at home Although it will compile, it can be dangerous to your sanity.)

END LOOP month_loop;

END LOOP year_loop;

The IF statement references the date_number loop index of both the outer and inner loops by

prefixing the outer loop's name to the first reference to date_number, I tell the compiler which

variable I want it to use

Again, you would be much better off simply changing the name of one or both of the loop indexes; date_number is much too vague a name for either of these loops

Trang 21

Previous: 7.5 The WHILE

Loop

Oracle PL/SQL Programming, 2nd Edition

Next: 7.7 Tips for PL/SQL Loops

The Oracle Library

Navigation

Copyright (c) 2000 O'Reilly & Associates All rights reserved

Trang 22

Previous: 7.4 The Cursor

FOR Loop

Chapter 7Loops

Next: 7.6 Managing Loop Execution

7.5 The WHILE Loop

The WHILE loop is a conditional loop that continues to execute as long as the Boolean condition defined in the loop boundary evaluates to TRUE Because the WHILE loop execution depends on a condition and is not fixed, use a WHILE loop if you don't know ahead of time the number of times a loop must execute

Here is the general syntax for the WHILE loop:

How the loop is terminated The WHILE loop terminates when the Boolean expression in

its boundary evaluates to FALSE or NULL

Trang 23

When the test for termination

takes place

The test for termination of a WHILE loop takes place in the loop boundary This evaluation occurs prior to the first and each subsequent execution of the body The WHILE loop, therefore, cannot be guaranteed to always execute its loop even

a single time

Reason to use this loop Use the WHILE loop when:

● You are not sure how many times you must execute the loop body, and

● You will want to conditionally terminate the loop, and

● You don't have to execute the body at least one time

The WHILE loop's condition is tested at the beginning of the loop's iteration, before the body of the loop is executed There are two consequences to this pre-execution test:

● All the information needed to evaluate the condition must be set before the loop is executed for the first time

● It is possible that the WHILE loop will not execute even a single time

7.5.1 The Infinite WHILE Loop

One of the dangers of the simple loop is that it could be an infinite loop if the body of the loop never executes an EXIT statement While this is less of a problem with the WHILE loop, you should be aware that it is certainly possible to construct a WHILE loop that is syntactically equivalent to the infinite LOOP The most obvious version of an infinite WHILE loop is the following:

Trang 24

information you need to resolve the problem is not readily available

Previous: 7.4 The Cursor

FOR Loop

Oracle PL/SQL Programming, 2nd Edition

Next: 7.6 Managing Loop Execution

7.4 The Cursor FOR Loop Book Index 7.6 Managing Loop Execution

The Oracle Library

Navigation

Copyright (c) 2000 O'Reilly & Associates All rights reserved

Trang 25

Previous: 7.3 The Numeric

FOR Loop

Chapter 7Loops

Next: 7.5 The WHILE Loop

7.4 The Cursor FOR Loop

A cursor FOR loop is a loop that is associated with (actually defined by) an explicit cursor or a

SELECT statement incorporated directly within the loop boundary Use the cursor FOR loop

whenever (and only if) you need to fetch and process each and every record from a cursor, which is a high percentage of the time with cursors

The cursor FOR loop is one of my favorite PL/SQL features It leverages fully the tight and effective integration of the procedural constructs with the power of the SQL database language It reduces the volume of code you need to write to fetch data from a cursor It greatly lessens the chance of

introducing loop errors in your programming and loops are one of the more error-prone parts of a program Does this loop sound too good to be true? Well, it isn't it's all true!

Here is the basic syntax of a cursor FOR loop:

FOR record_index IN cursor_name

LOOP

<executable statement(s)>

END LOOP;

where record_index is a record declared implicitly by PL/SQL with the %ROWTYPE attribute

against the cursor specified by cursor_name

The following table summarizes the properties of the cursor FOR loop where record_index is a record declared implicitly by PL/SQL with the %ROWTYPE attribute against the cursor specified by

cursor_name:

Ngày đăng: 17/10/2013, 22:15

TỪ KHÓA LIÊN QUAN