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
207,49 KB
Nội dung
3. Using another exception section within the first exception section, trap this exception as the
"else" in this pseudo-IF statement. Within the exception handler, try to convert the string with
TO_DATE and the third mask, MM/YY. If it works, I am done. If it doesn't work, an
exception is raised.
4. I have only three masks, so if I cannot convert the string after these three TO_DATE calls, the
user entry is invalid and I will simply return NULL.
The function convert_date that follows illustrates the full PL/SQL version of the preceding
pseudocode description. I make liberal use of the WHEN OTHERS exception handler because I have
no way of knowing which exception would have been raised by the conversion attempt:
FUNCTION convert_date (value_in IN VARCHAR2) RETURN DATE
IS
return_value DATE;
BEGIN
IF value_int IS NULL THEN return_value := NULL;
ELSE
BEGIN
/* IF MM/DD/YY mask works, set return value. */
return_value := TO_DATE (value_in, 'MM/DD/YY');
EXCEPTION
/* OTHERWISE: */
WHEN OTHERS THEN
BEGIN
/* IF DD-MON-YY mask works, set return
value. */
return_value := TO_DATE (value_in, 'DD-MON-
YY');
EXCEPTION
/* OTHERWISE: */
WHEN OTHERS THEN
BEGIN
/* IF MM/YY mask works, set return
value. */
return_value := TO_DATE (value_in,
'MM/YY');
EXCEPTION
/* OTHERWISE RETURN NULL. */
WHEN OTHERS THEN
return_value := NULL;
END;
END;
END;
END IF;
RETURN (return_value);
END;
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Previous: 8.8
NO_DATA_FOUND:
Multipurpose Exception
Oracle PL/SQL
Programming, 2nd Edition
Next: 8.10 RAISE Nothing
but Exceptions
8.8 NO_DATA_FOUND:
Multipurpose Exception
Book Index
8.10 RAISE Nothing but
Exceptions
The Oracle Library
Navigation
Copyright (c) 2000 O'Reilly & Associates. All rights reserved.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Previous: 8.9 Exception
Handler as IF Statement
Chapter 8
Exception Handlers
Next: 9. Records in PL/SQL
8.10 RAISE Nothing but Exceptions
Have you noticed that the RAISE statement acts in many ways like a GOTO statement? The GOTO
statement in PL/SQL looks like this:
GOTO label_name;
where label_name is the name of a label. This label is placed in a program as follows:
<<label_name>>
When PL/SQL encounters a GOTO statement, it immediately shifts control to the first executable
statement following the label (which must still be in the execution section of the PL/SQL block). The
RAISE statement works much the same way: when PL/SQL encounters a RAISE, it immediately
shifts control to the exception section, and then looks for a matching exception.
A very significant and fundamental difference between GOTO and RAISE, however, is that GOTO
branches to another execution statement, whereas RAISE branches to the exception section. The
RAISE statement, in other words, shifts the focus of the program from normal execution to "error
handling mode." Both from the standpoint of code readability and also of maintenance, you should
never use the RAISE statement as a substitute for a control structure, be it a GOTO or an IF
statement.
If you have not tried to use RAISE in this way, you might think that I am building up a straw man in
order to knock it down. Would that it were so. Just in the process of writing this book, I ran across
several examples of this abuse of exception handling. Check out, for example, the function
description for GET_GROUP_CHAR_CELL in Oracle Corporation's Oracle Forms Reference
Volume 1. It offers a function called Is_Value_In_List, which returns the row number of the value if
it is found in the record group, as an example of a way to use GET_GROUP_CHAR_CELL.
The central logic of Is_Value_In_List is shown in the following example. The function contains three
different RAISE statements all of which raise the exit_function exception:
1 FUNCTION Is_Value_In_List
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
2 (value VARCHAR2, rg_name VARCHAR2, rg_column
VARCHAR2)
3 RETURN NUMBER
4 IS
5 Exit_Function EXCEPTION;
6 BEGIN
7 If bad-inputs THEN
8 RAISE Exit_Function;
9 END IF;
10
11 LOOP-through-record-group
12 IF match-found
13 RAISE Return_Value;
14 END IF;
15 END LOOP;
16
17 RAISE Exit_Function;
18
19 EXCEPTION
20 WHEN Return_Value THEN
21 RETURN row#;
22
23 WHEN Exit_Function THEN
24 RETURN 0;
25 END;
The first RAISE on line 8 is an appropriate use of an exception because we have an invalid data
structure. The function should bail out.
The second RAISE on line 13 is, however, less justifiable. This RAISE is used to end the program
and return the row in which the match was found. An exception is, in this case, used for successful
completion.
Exception Handling Quick Facts and Tips
Here are some facts and tips to remember about exception handling:
● The exception section of a PL/SQL block only handles exceptions raised in the execution
section of that block.
● An exception raised in the declaration section of a PL/SQL block is handled by the exception
section of the enclosing block, if it exists.
● An exception raised in the exception section of a PL/SQL block is handled by the exception
section of the enclosing block, if it exists.
● Use WHEN OTHERS when you want to trap and handle all exceptions in a PL/SQL block.
● Once an exception is raised, the block's execution section is terminated and control is
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
transferred to the exception section. You cannot return to that execution section after the
exception is raised.
● After an exception is handled, the next executable statement in the enclosing block is
executed.
● To handle a specific exception, it must have a name. You declare exceptions to give them
names.
● Once you have handled an exception, normal program execution continues. You are no longer
in an "exception" situation.
The third RAISE on line 17 is also questionable. This RAISE is the very last statement of the
function. Now, to my mind, the last line of a function should be a RETURN statement. The whole
point of the function, after all, is to return a value. In this case, however, the last line is an exception,
because the author has structured the code so that if I got this far, I have not found a match. So raise
the exception, right? Wrong.
"Row-not-found" is not an exception from the standpoint of the function. That condition should be
considered one of the valid return values of a function that asks "Is value in list?" This function
should be restructured so that the exception is raised only when there is a problem.
From the perspective of structured exception handling in PL/SQL, this function suffered from several
weaknesses:
Poorly named exceptions
The exception names exit_function and return_value describe actions, rather than error
conditions. The name of an exception should describe the error which took place.
Exceptions for valid outcomes
By using these "action" names, the developers are actually being very open about how they
are manipulating the exception handler. They say, "I use exceptions to implement logic
branching." We should say to them, "Don't do it! Use the constructs PL/SQL provides to
handle this code in a structured way."
If you encounter either of these conditions in code you are writing or reviewing, take a step back.
Examine the logical flow of the program and see how you can use the standard control structures (IF,
LOOP, and perhaps even GOTO) to accomplish your task. The result will be much more readable
and maintainable code.
Previous: 8.9 Exception
Handler as IF Statement
Oracle PL/SQL
Programming, 2nd Edition
Next: 9. Records in PL/SQL
8.9 Exception Handler as IF
Statement
Book Index
9. Records in PL/SQL
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
The Oracle Library
Navigation
Copyright (c) 2000 O'Reilly & Associates. All rights reserved.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Previous: 8.10 RAISE
Nothing but Exceptions
Chapter 9
Next: 9.2 Table-Based
Records
9. Records in PL/SQL
Contents:
Record Basics
Table-Based Records
Cursor-Based Records
Programmer-Defined Records
Assigning Values to and from Records
Record Types and Record Compatibility
Nested Records
Records in PL/SQL programs are very similar in concept and structure to the rows of a database
table. A record is a composite data structure, which means that it is composed of more than one
element or component, each with its own value. The record as a whole does not have value of its
own; instead, each individual component or field has a value. The record gives you a way to store and
access these values as a group.
If you are not familiar with using records in your programs, you might initially find them
complicated. When used properly, however, records will greatly simplify your life as a programmer.
You will often need to transfer data from the database into PL/SQL structures and then use the
procedural language to further massage, change, or display that data. When you use a cursor to read
information from the database, for example, you can pass that table's record directly into a single PL/
SQL record. When you do this you preserve the relationship between all the attributes from the table.
9.1 Record Basics
This section introduces the different types of records and the benefits of using them in your programs.
9.1.1 Different Types of Records
PL/SQL supports three different kinds of records: table-based, cursor-based, and programmer-
defined. These different types of records are used in different ways and for different purposes, but all
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
three share the same internal structure: every record is composed of one or more fields. However, the
way these fields are defined in the record depend on the record type. Table 9.1 shows this information
about each record type.
Table 9.1: PL/SQL Record Types
Record Type Description Fields in Record
Table-based A record based on a table's column
structure.
Each field corresponds to and has
the same name as a column in a
table.
Cursor-based A record based on the cursor's
SELECT statement.
Each field corresponds to a column
or expression in the cursor SELECT
statement.
Programmer-
defined
A record whose structure you, the
programmer, get to define with a
declaration statement.
Each field is defined explicitly (its
name and datatype) in the TYPE
statement for that record; a field in a
programmer-defined record can
even be another record.
Figure 9.1 illustrates the way a cursor record adopts the structure of the SELECT statement by using
the %ROWTYPE declaration attribute (explained later in this chapter).
Figure 9.1: Mapping of cursor structure to PL/SQL record
9.1.2 Accessing Record-Based Data
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
You access the fields within a record using dot notation, just as you would identify a column from a
database table, in the following format:
<record name>.<field name>
You would reference the first_name column from the employee table as follows:
employee.first_name
You would reference the emp_full_name field in the employee PL/SQL record as:
employee_rec.emp_full_name
The record or tuple structure of relational database tables has proven to be a very powerful way to
represent data in a database, and records in your programs offer similar advantages. The next section
describes briefly the reasons you might want to use records. The rest of this chapter show you how to
define and use each of the different types of records, and the situations appropriate to each record
type.
9.1.3 Benefits of Using Records
The record data structure provides a high-level way of addressing and manipulating program-based
data. This approach offers the following benefits:
Data abstraction
Instead of working with individual attributes of an entity or object, you think of and
manipulate that entity as a "thing in itself."
Aggregate operations
You can perform operations which apply to all the columns of a record.
Leaner, cleaner code
You can write less code and make what you do write more understandable.
The following sections describe each of these benefits.
9.1.3.1 Data abstraction
When you abstract something, you generalize it. You distance yourself from the nitty-gritty details
and concentrate on the big picture. When you create modules, you abstract the individual actions of
the module into a name. The name (and program specification) represents those actions.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
When you create a record, you abstract all the different attributes or fields of the subject of that
record. You establish a relationship between all those different attributes and you give that
relationship a name by defining a record.
9.1.3.2 Aggregate operations
Once you have stored information in records, you can perform operations on whole blocks of data at
a time, rather than on each individual attribute. This kind of aggregate operation reinforces the
abstraction of the record. Very often you are not really interested in making changes to individual
components of a record, but instead to the object which represents all of those different components.
Suppose that in my job I need to work with companies, but I don't really care about whether a
company has two lines of address information or three. I want to work at the level of the company
itself, making changes to, deleting, or analyzing the status of a company. In all these cases I am
talking about a whole row in the database, not any specific column. The company record hides all
that information from me, yet makes it accessible when and if I need it. This orientation brings you
closer to viewing your data as a collection of objects with rules applied to those objects.
9.1.3.3 Leaner, cleaner code
Using records also helps you to write clearer code and less of it. When I use records, I invariably
produce programs which have fewer lines of code, are less vulnerable to change, and need fewer
comments. Records also cut down on variable sprawl; instead of declaring many individual variables,
I declare a single record. This lack of clutter creates aesthetically attractive code which requires fewer
resources to maintain.
9.1.4 Guidelines for Using Records
Use of PL/SQL records can have a dramatic impact on your programs, both in initial development
and in ongoing maintenance. To ensure that I personally get the most out of record structures, I have
set the following guidelines for my development:
● Create corresponding cursors and records. Whenever I create a cursor in my programs, I also
create a corresponding record (except in the case of cursor FOR loops). I always FETCH into
a record, rather than into individual variables. In those few instances when it might involve a
little extra work over simply fetching into a single variable, I marvel at the elegance of this
approach and compliment myself on my commitment to principle.
● Create table-based records. Whenever I need to store table-based data within my programs, I
create a new (or use a predefined) table-based record to store that data. I keep my variable use
to a minimum and dynamically link my program data structures to my RDBMS data structures
with the %ROWTYPE attribute.
● Pass records as parameters. Whenever appropriate, I pass records rather than individual
variables as parameters in my procedural interfaces. This way, my procedure calls are less
likely to change over time, making my code more stable. There is a downside to this
technique, however: if a record is passed as an OUT or IN OUT parameter, its field values are
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
[...]... other words, no such thing as a "read-only" PL/SQL record structure Previous: 8.10 RAISE Nothing but Exceptions 8.10 RAISE Nothing but Exceptions Oracle PL/SQL Programming, 2nd Edition Book Index Next: 9.2 Table-Based Records 9.2 Table-Based Records The Oracle Library Navigation Copyright (c) 2000 O'Reilly & Associates All rights reserved Please purchase PDF Split-Merge on www.verypdf.com to remove... strong reliance on data manipulation through records, however, you can keep such references to a minimum Previous: 9.1 Record Basics 9.1 Record Basics Oracle PL/SQL Programming, 2nd Edition Book Index Next: 9.3 Cursor-Based Records 9.3 Cursor-Based Records The Oracle Library Navigation Copyright (c) 2000 O'Reilly & Associates All rights reserved Please purchase PDF Split-Merge on www.verypdf.com to remove... are restricted in how they can interact, a topic we will explore in the next section Previous: 9.2 Table-Based Records 9.2 Table-Based Records Oracle PL/SQL Programming, 2nd Edition Book Index Next: 9.4 ProgrammerDefined Records 9.4 Programmer-Defined Records The Oracle Library Navigation Copyright (c) 2000 O'Reilly & Associates All rights reserved Please purchase PDF Split-Merge on www.verypdf.com to... actually records within records, and with fields that are PL/SQL tables Previous: 9.3 Cursor-Based Records 9.3 Cursor-Based Records Oracle PL/SQL Programming, 2nd Edition Book Index Next: 9.5 Assigning Values to and from Records 9.5 Assigning Values to and from Records The Oracle Library Navigation Copyright (c) 2000 O'Reilly & Associates All rights reserved Please purchase PDF Split-Merge on www.verypdf.com... use of aggregate assignments and other record operations Previous: 9.4 ProgrammerDefined Records 9.4 Programmer-Defined Records Oracle PL/SQL Next: 9.6 Record Types Programming, 2nd Edition and Record Compatibility 9.6 Record Types and Record Book Index Compatibility The Oracle Library Navigation Copyright (c) 2000 O'Reilly & Associates All rights reserved Please purchase PDF Split-Merge on www.verypdf.com... assignment must be based on the same TYPE RECORD statement 9.6.1.3 Setting records to NULL In earlier versions of Oracle (7.2 and below), the following assignmentwould cause an erroor: comp_sales_rec := NULL; NULL was treated as a scalar value, and would not be applied to each of the record's fields In Oracle 7.3 and above, the assignment of NULL to a record is allowed, and will set each of the fields back... RECORD (nested_rec first_rectype := first_rec); BEGIN END; Previous: 9.5 Assigning Values to and from Records 9.5 Assigning Values to and from Records Oracle PL/SQL Programming, 2nd Edition Book Index Next: 9.7 Nested Records 9.7 Nested Records The Oracle Library Navigation Copyright (c) 2000 O'Reilly & Associates All rights reserved Please purchase PDF Split-Merge on www.verypdf.com to remove this... Programmer-Defined Records Now you know how to create a record with the same structure as a table or a cursor These are certainly very useful constructs in a programming language designed to interface with the Oracle RDBMS Yet do these kinds of records cover all of our needs for composite data structures? What if I want to create a record that has nothing to do with either a table or a cursor? What if I want . example, the function
description for GET_GROUP_CHAR_CELL in Oracle Corporation's Oracle Forms Reference
Volume 1. It offers a function called Is_Value_In_List,. Exceptions
Oracle PL/SQL
Programming, 2nd Edition
Next: 9.2 Table-Based
Records
8.10 RAISE Nothing but
Exceptions
Book Index
9.2 Table-Based Records
The Oracle