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

Oracle PLSQL Language- P24

50 328 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 đề Oracle plsql language - p24
Trường học University of Example
Chuyên ngành Computer Science
Thể loại Thesis
Năm xuất bản 2023
Thành phố example city
Định dạng
Số trang 50
Dung lượng 148,17 KB

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

Nội dung

Consider this Oracle Forms function, which retrieves the name of a company from its primary key: FUNCTION company_name company_id_in IN company.company_id %TYPE RETURN VARCHAR2 IS CURS

Trang 1

assignment operator itself already serves as the "action" for that statement

I can make a few, minor adjustments in these module names and end up with much more readable code, as shown in this example:

Trang 2

net_profit_for_single_company

Don't forget that you or someone else will have to type those program names!

22.1.2 Develop Consistent Naming Conventions for Your Formal

Parameters

A parameter plays a specific role within a program; its name should indicate this difference I

recommend that in order to further distinguish parameters from other PL/SQL identifiers you include the parameter mode right in the name of the formal parameter

A parameter has one of three modes: IN, OUT, or IN OUT An IN parameter passes a value into the module, but its value cannot be modified An OUT parameter passes a value out of the module, but its value cannot be referenced in the module An IN OUT parameter can be both referenced and modified in the module

By incorporating the parameter mode directly into the parameter name, its purpose in the module is self-documenting Whenever you encounter that parameter in the code, you know that you are

looking at a parameter, not a local variable, and you know exactly the ways in which that parameter can be used and/or changed

In order for the parameter mode to stand out in the formal parameter name, you can include it either

as a suffix or as a prefix As a suffix, the mode is appended to the end of the parameter name, as follows:

PROCEDURE combine_and_format_names

(first_name_inout IN OUT VARCHAR2,

last_name_inout IN OUT VARCHAR2,

full_name_out OUT VARCHAR2,

name_format_in IN VARCHAR2 := 'LAST,FIRST');

The prefix standard would result in a parameter list for the above procedure as follows:

PROCEDURE combine_and_format_names

(inout_first_name IN OUT VARCHAR2,

inout_last_name IN OUT VARCHAR2,

out_full_name OUT VARCHAR2,

in_name_format IN VARCHAR2 := 'LAST,FIRST') ;

You could also opt for a minimum of typing by simply using the first letter of each parameter mode:

PROCEDURE combine_and_format_names

(io_first_name IN OUT VARCHAR2,

Trang 3

io_last_name IN OUT VARCHAR2,

o_full_name OUT VARCHAR2,

i_name_format IN VARCHAR2 := 'LAST,FIRST') ;

In any of these cases, a quick glance over the code identifies which objects represent parameters in the program You can also more easily catch logic errors, such as the following case of an illegal update of an IN parameter:

in_name_format := 'FIRST MIDDLE LAST';

A parameter with an "in" suffix or prefix should never have its value changed A parameter with an

"out" suffix or prefix should never be used on the right-hand side of an assignment because its value

is indeterminate in the program (until it is given a value)

22.1.3 Name Packages and Their Elements to Reflect the Packaged

Structure

Given that a package provides a new layer or context over the normal variables and modules, you should take some special care in naming your packages and the elements within them The name you use for a standalone module, in particular, will change when you move it inside a package Consider the following example If I develop a set of standalone procedures and functions to maintain lists of information, I might name them as follows:

PROCEDURE list_create (list_in IN VARCHAR2);

(list_in IN VARCHAR2, position_in IN NUMBER,

item_out OUT VARCHAR2);

END list;

At first glance this looks reasonable enough The real test, however, comes when you try to use the modules Let's try it To create a list using the package procedure, I would execute a statement like

Trang 4

this:

list_pkg.list_create ('company_names');

Now, that looks silly The "list" is mentioned in both the package name and the module name It didn't make much sense to carry over the standalone module names to the package names A much cleaner naming scheme should produce executable statements that remove the redundancies:

PACKAGE list_pkg

IS

PROCEDURE create (list_in IN VARCHAR2);

PROCEDURE get

(list_in IN VARCHAR2, position_in IN NUMBER,

item_out OUT VARCHAR2);

(list_in IN VARCHAR2, position_in IN NUMBER,

item_out OUT VARCHAR2);

indicator) reduces the readability of the code

Trang 5

Previous: VI Making PL/

SQL Programs Work

Oracle PL/SQL Programming, 2nd Edition

Next: 22.2 Build the Most Functional Functions

Trang 6

Previous: 22.1 Select

Meaningful Module and

Parameter Names

Chapter 22Code Design Tips

Next: 22.3 Take Full Advantage of Local Modularization

22.2 Build the Most Functional Functions

I like functions They can replace an awful lot of complex logic in an expression with a simple

statement of the result of all that logic The following tips will help you construct functions that are as useful as possible

22.2.1 Avoid Side Effects in Functions

Your function has one purpose in life: returning a single value via the RETURN statement If it does anything else, such as update global or database information, then that function has potentially

created a side effect Side effects generally limit functions' usefulness Let's look at a few examples and discuss how you can avoid side effects

22.2.1.1 Do not use OUT and IN OUT parameters

Although a function returns its value with the RETURN statement, PL/SQL allows you to define OUT and IN OUT parameters for a function If you do that, the function can actually pass changed data back through the parameter itself into the calling block of code through the parameters This is generally not a good idea, and is a typical side effect in a function

The format_name function below contains side effect parameters Let's examine the impact of these parameters The function takes a first name and a last name and returns a full name with the format LAST, FIRST Because a requirement of the application happens to be that all names must be in uppercase, the function also converts the first and last names to their uppercase versions It uses two

IN OUT parameters to do this

FUNCTION format_name

(first_name_inout IN OUT VARCHAR2,

last_name_inout IN OUT VARCHAR2)

Trang 7

last_name_inout := UPPER (last_name_inout);

RETURN last_name_inout || ', ' || first_name_inout;

END;

If the application requires uppercase names, you may wonder, then, what is wrong with converting the first and last names to uppercase in format_name? First of all, this approach may be trying to meet the requirement a bit too enthusiastically If the formatted name the output, that is, of the function must be in uppercase, you can certainly accomplish that without modifying the

22.2.1.2 Switch to a procedure with IN OUT parameters

If you do want a module that will convert both individual name components and the combined name

to uppercase, then you would be better served with a procedure:

PROCEDURE combine_and_format_names

(first_name_inout IN OUT VARCHAR2,

last_name_inout IN OUT VARCHAR2,

full_name_out OUT VARCHAR2)

IS

BEGIN

first_name_inout := UPPER (first_name_inout);

last_name_inout := UPPER (last_name_inout);

Trang 8

You avoid providing a function with side effects (i.e., other actions and impact beyond the return of a value) Let's take a look at the way these different modules would appear in your code

● Let's first look at the function version All our attention is focused on depositing the formatted name into the caller_name item:

full_name := format_name (first_name, :last_name);

● Now let's look at the procedure version The use of the plural of "name" in the name of the procedure indicates a change to more than one of the parameters:

combine_and_format_names (first_name, last_name, full_name);

Generally speaking, when your function has a side effect such as the uppercasing of the parameter values, that function is less broadly useful What if programmers don't want to have the other values uppercased? They would have to write their own function that does the same thing as format_name, but without the UPPER statements This code redundancy will create nightmares down the road If the function is supposed to return a formatted name based on the first and last names, then that is all it should do never use OUT and IN OUT parameters with a function

22.2.1.3 Don't interact with users

Such parameters are not the only kinds of side effects you may be tempted to slip into a function Consider this Oracle Forms function, which retrieves the name of a company from its primary key:

FUNCTION company_name (company_id_in IN company.company_id

%TYPE)

RETURN VARCHAR2

IS

CURSOR name_cur IS

SELECT name FROM company

WHERE company_id = company_id_in;

Trang 9

ACKNOWLEDGE);

RAISE FORM_TRIGGER_FAILURE;

END IF;

END;

When the company ID returns an existing company, the function properly closes the cursor and

returns the company's name When the SELECT statement comes up empty, however, I change my approach completely Rather than return a value, I go into the equivalent of PL/SQL panic mode: ring the bell, display a message (and force the user to acknowledge that message), and then fail out of the calling trigger I don't even close the cursor! Rather strong stuff, and very much out of place in this function

My response to invalid data is a side effect in the function, made all the worse by the fact that my side effect completely substitutes for a RETURN When the company ID does not find a match, I do not execute a RETURN statement at all

The consequences of my error handling in this function are:

● This function can be called only in Oracle Forms It is, however, a fairly generic task: take a primary key and return a name/description It could be a function stored in the database and available to any program that needs to perform the lookup I have now made that impossible

● Anyone who calls this function gives up control over his or her own program You cannot decide for yourself what to do if the name is not found That message is displayed whether or not it is appropriate That bell sounds even if users don't like to announce to everyone around them that they made a mistake The best you can do is code an exception handler for

FORM_TRIGGER_FAILURE in whatever trigger or program calls company_name

A much better approach to the company_name function is simply to return a NULL value if the

company is not found Since the company name is a NOT NULL column, a NULL return value

clearly indicates "no data found." This new approach is shown in the following example:

FUNCTION company_name (company_id_in IN company.company_id

%TYPE)

RETURN VARCHAR2

IS

CURSOR name_cur IS

SELECT name FROM company

WHERE company_id = company_id_in;

Trang 10

on an appropriate consequence, which might well consist of every action formerly embedded in the function itself:

new_company := company_name (:company.company_id);

At least now the programmer has freedom of choice

Side effects in functions come in many shapes and flavors If you remember to keep the focus of the function on computing and returning its value, the resulting module will be more effectively and widely used

22.2.2 Use a Single RETURN Statement for Successful Termination

A function exists to return a single value The best way to structurally emphasize this single-minded focus in the body of the function is to make sure that the only RETURN statement in the execution section of the function is the last executable statement Consider the following code-translating function:

FUNCTION status_desc (status_cd_in IN VARCHAR2) RETURN

VARCHAR2

Trang 11

BEGIN

IF status_cd_in = 'C' THEN RETURN 'CLOSED';

ELSIF status_cd_in = 'O' THEN RETURN 'OPEN';

ELSIF status_cd_in = 'A' THEN RETURN 'ACTIVE';

ELSIF status_cd_in = 'I' THEN RETURN 'INACTIVE';

END IF;

END;

Each of the different RETURN statements is actually a different exit point in this function You are now probably saying to yourself, "This is such a simple program What's wrong with using the

different RETURN statements?"

Granted, the program is straightforward and short enough so that, at a glance, you understand its purpose and follow the exit flow Unfortunately, it also is prone to failure What if the status code that

is passed into status_desc is not one of C, O, A, or I? Then the function does not even execute a

RETURN statement, leaving the calling program with indeterminate results Now examine the

version of status_desc that relies on a single RETURN:

FUNCTION status_desc (status_cd_in IN VARCHAR2) RETURN

VARCHAR2

IS

return_value VARCHAR2 (20) := NULL;

BEGIN

IF status_cd_in = 'C' THEN return_value := 'CLOSED';

ELSIF status_cd_in = 'O' THEN return_value := 'OPEN';

ELSIF status_cd_in = 'A' THEN return_value := 'ACTIVE';

ELSIF status_cd_in = 'I' THEN return_value :=

'INACTIVE';

END IF;

RETURN return_value;

END;

Here, my IF statement assigns the description to a local variable After the IF statement, the

RETURN statement serves its purpose in life, which is to pass the value of the variable back to the calling program Because I initialize the temporary description to NULL, if the status code is not one

of the chosen four, then I return NULL In any case, the result is that, by placing the RETURN

statement at the last line of the execution section of the function, I always execute a RETURN

statement when the function completes successfully There are no holes in my return logic

This approach is absolutely critical when your function is more elaborate and longer than 10 or 20 lines in length, perhaps even hundreds of lines long It can be very difficult to follow multi-page complex logic, and nearly impossible to confirm, simply by reading the code, that the function

always issues a RETURN statement for all branches of the logic Your application works much more reliably if you build right into it the requirement that the only RETURN statement in the function

Trang 12

occurs at the end of the program

22.2.2.1 Build a function template

I realize that it is one thing to read through all of the tips in this book and, as you read them, nod in agreement with their wisdom It is quite another thing to both remember the tips and make the time to put them to use in your code The best way I have found to at least improve the chances that I follow even my own advice is to set hard and fast rules and then stick to them When it comes to "Use a single RETURN statement for successful termination," I try to always follow two simple rules when creating a function:

● Always declare a local variable named "return_value" with a datatype that matches the

RETURN clause of the function If I am returning a VARCHAR2, declare a VARCHAR2 local variable If I am returning data with the same datatype as a table column, declare that Here are two examples:

FUNCTION net_sales (company_id_in IN company

company_id%TYPE) RETURN NUMBERIS

return_value NUMBER;

BEGIN

END;

or:

FUNCTION company_name (company_id_in IN company

company_id%TYPE) RETURN company.name%TYPEIS

return_value company.name%TYPE;

BEGIN

END;

● Always make the last executable statement of my function the RETURN statement as follows:

RETURN return_value;

By following these two rules, the general structure of my function now looks like this:

FUNCTION function_name (parameter_list) RETURN datatype

Trang 13

RETURN return_value;

EXCEPTION

optional exception section

END;

The name of the local variable states quite clearly that it is standing in for the data that is to be

returned by the function Any time this return_value variable is assigned a value in the function, you know that the function is fulfilling its purpose of generating a value to be returned with the RETURN statement It provides a clean, understandable, and predictable structure for the function I have even gone so far as to create a template script on disk that implements this guideline It looks like this:

/* Filename on companion disk: functmpl.sf */

CREATE OR REPLACE FUNCTION fname () RETURN datatype

One exception to the rule of a single RETURN statement in a function concerns exception handling

A function should return a value, whether it completes successfully or it fails Upon successful

completion, you can use the above structure to guarantee that the RETURN executes What if the function fails? Any exception handler in a function should have as its last executable statement a RETURN of its own, as this example shows:

Trang 14

problem Do not process the error inline PL/SQL provides a very structured distinction between the executable body of the program and the exception section As soon as you hit an error or logical exception to normal processing, RAISE an exception to transfer control out of normal execution

22.2.3 Avoid Exception Handlers for Normal Program Exits

There is always only one entry point for a module: the first executable statement is always the one that follows the BEGIN statement PL/SQL does not allow you to enter a block at an arbitrary line of code The same cannot be said, however, for the way in which a module terminates A PL/SQL

program unit may complete its execution either through the last executable statement, a RETURN statement, or the exception handler section, as is appropriate:

● The last executable statement in a program is the normal exit point for a procedure

● The RETURN statement is the normal exit point for a function

● The exception section is the way out of a module that has hit an error and raised an exception

A programming language like PL/SQL is constructed very carefully: every keyword and element of syntax is chosen with a specific purpose Although you can at times justify using a language construct

in an unorthodox way, in most cases such an action will raise a red flag and be closely examined One example of such linguistic abuse occurs when a programmer uses an exception handler to perform a normal program exit Here is an example:

FUNCTION company_name (company_id_in IN company.company_id

SELECT name INTO cname FROM company

WHERE company_id = company_id_in;

RAISE found_it;

Trang 15

The found_it exception is not an exception at all It indicates successful completion of the program Rather than use an exception, the function should simply issue a RETURN with cname, indicating that the SELECT was successful:

FUNCTION company_name (company_id_in IN company.company_id

SELECT name INTO cname FROM company

WHERE company_id = company_id_in;

Programmers are often tempted to use the RAISE statement because it acts like a GOTO: it

immediately halts execution of the program and transfers control to the exception section This GOTO-like behavior can be very convenient when a programmer cannot figure out how to use IF statements in a structured way to neatly end the program In this case, the RAISE statement becomes

an easy way out

If you find yourself writing programs that rely on the RAISE statement to do something besides handle exceptions, take a step back Examine the logical flow of the program and explore how you can use the standard control structures (IF, LOOP, and perhaps even GOTO as a last resort) to

accomplish your task instead

Trang 16

22.2.4 Use Assertion Modules to Validate Parameters and Assumptions

Just about every piece of software you write makes assumptions about the data it manipulates For example, parameters may have only certain values or be within a certain range, or a string value should have a certain format In both of these cases, an underlying data structure is assumed to have been created It's fine to have such rules and assumptions, but it is also very important to verify or

"assert" that none of the rules is being violated

One approach you can take in this verification process is to make use of the IF statement at the

beginning of your program The status_desc function shown below uses the conditional construct to implicitly validate the value of the argument The function does not actively or explicitly check to see

if the status code argument is one of C, O, A, or I Instead, the IF statement returns a non-null value only if a valid code is provided

FUNCTION status_desc (status_cd_in IN VARCHAR2) RETURN

VARCHAR2

IS

return_value VARCHAR2 (20) := NULL;

BEGIN

IF status_cd_in = 'C' THEN return_value := 'CLOSED';

ELSIF status_cd_in = 'O' THEN return_value := 'OPEN';

ELSIF status_cd_in = 'A' THEN return_value := 'ACTIVE';

ELSIF status_cd_in = 'I' THEN return_value :=

On the other hand, what if a legal value should always be passed to status_desc? What if a different value means that a programmer has coded her use of the function improperly? If status_desc is an

"internal" function accessed only by programmers and not intended to handle user input, then an illegal status code probably reflects a typographical error or a misunderstanding of the program's use

In this case, the lack of feedback by status_desc on the invalid argument results in hard-to-trace

errors Because the programmer is not informed of the typographical mistake when it happens, the problem propagates through other modules before it surfaces

22.2.4.1 Trap invalid argument values

If the status_desc function is built to accept only four valid entries, then it should raise a red flag when that rule is broken The following function shows a version of status_desc that adds an ELSE

Trang 17

clause to trap an invalid entry:

FUNCTION status_desc (status_cd_in IN VARCHAR2) RETURN

VARCHAR2

IS

return_value VARCHAR2 (20) := NULL;

BEGIN

IF status_cd_in = 'C' THEN return_value := 'CLOSED';

ELSIF status_cd_in = 'O' THEN return_value := 'OPEN';

ELSIF status_cd_in = 'A' THEN return_value := 'ACTIVE';

ELSIF status_cd_in = 'I' THEN return_value :=

With this new version, programmers get immediate feedback if they pass an illegal value to

status_desc That problem is solved, but I personally find this solution less than totally satisfactory Since it forces me to add several lines of code to the body of my program lines that were added simply to handle values that never should have gotten into the program this approach is somewhat intrusive and inelegant Consider the alternative below:

FUNCTION status_desc (status_cd_in IN VARCHAR2) RETURN

VARCHAR2

IS

return_value VARCHAR2 (20) := NULL;

BEGIN

/* Assert that the status code is valid */

assert_condition (status_cd_in IN ('C', 'O', 'A',

'I'));

/* Now perform processing of valid argument */

IF status_cd_in = 'C' THEN return_value := 'CLOSED';

ELSIF status_cd_in = 'O' THEN return_value := 'OPEN';

ELSIF status_cd_in = 'A' THEN return_value := 'ACTIVE';

ELSIF status_cd_in = 'I' THEN return_value :=

'INACTIVE';

END IF;

RETURN return_value;

END;

Trang 18

The procedure, assert_condition, looks like this:

PROCEDURE assert_condition (condition_in IN BOOLEAN)

status_cd_in IN ('C', 'O', 'A', 'I')

This kind of a program is called an assertion module because its single Boolean parameter asserts

that a condition is true, and leaves it to the module to reject that claim Clearly, there isn't much to assert_condition It just hides an IF statement behind a procedural interface Yet, by including the call

to assert_condition, I can let the remainder of the body of my program concentrate on handling the valid data properly I do not have to include special handling for illegal values

Because assert_condition is very generic, I can use it in any program that has a condition I can

express in a single Boolean expression I don't have to code special nested logic repeatedly I tell assert_condition what rule I want to test, and leave it to the module to take action (raise an exception) when necessary

22.2.4.2 An application-specific assertion module

Of course, you can build less generic versions of assert_condition The next function shows an

assertion module for Oracle Forms that displays an optional message to the screen:

Trang 19

/* Raise an exception specific to Oracle Forms */

RAISE FORM_TRIGGER_FAILURE;

END IF;

END;

You can even produce assertion modules that handle very specific kinds of conditions If you do a lot

of work with record groups in Oracle Forms, you find yourself checking repeatedly at the beginning

of your program to see that the name or handle for the record group points to a valid record group You do this with the ID_NULL and FIND_GROUP built-ins, as follows:

IF ID_NULL (FIND_GROUP ('monthly_sales'))

Then simply call that assertion program:

PROCEDURE assert_valid_group (rg_name_in IN VARCHAR2)

/*

|| Assertion: if there is not a valid Id for the record

|| group, display message and raise exception This is a

|| "design" error; code should not continue executing

Trang 20

22.2.4.3 Is an assertion module a side effect?

But wait If I call assert_condition from within a function and the assertion fails, the function will not execute a RETURN statement Doesn't the use of an assertion module violate my guideline to always return a value from a function? The assert_condition procedure bails out of the calling module (or at least forces a transfer to the exception section) without any regard for whether a RETURN statement

is needed Even worse, doesn't the Oracle Forms version containing a MESSAGE statement

contradict my suggestion to avoid side effects in a function?

Yes and no Yes, I admit that when assert_condition RAISEs its exception, you do not issue a

RETURN statement (unless you code for it yourself in the function, but then you would have to know which exception was RAISEd by assert_condition) I also admit that the MESSAGE is a side effect in the function, the main purpose of which is to return a row number in a table

But I can explain everything, honest!

You see, the point of assert_condition is to test the underlying assumptions in the very structure of the module If status_desc is called with an invalid code, that kind of error is very different from, say,

a NO_DATA_FOUND when obtaining the name for a particular company ID number The

status_desc function as a whole is invalid if it is not passed a valid code In this context, it doesn't even make sense to continue processing The assert_condition procedure uncovers design level errors

in the code that must be corrected before you can even worry about data entry errors or other

application-level concerns

The logic behind assert_condition is similar to the way Oracle Forms handles level 25 errors when it executes a form No matter how high a value you have set for SYSTEM.MESSAGE_LEVEL, Oracle Forms always halts processing in a form when it encounters a level 25 error, which indicates a design error in the application

Previous: 22.1 Select

Meaningful Module and

Parameter Names

Oracle PL/SQL Programming, 2nd Edition

Next: 22.3 Take Full Advantage of Local Modularization

Trang 21

22.1 Select Meaningful

Module and Parameter Names

Book Index 22.3 Take Full Advantage of

Trang 22

Previous: 22.2 Build the

Most Functional Functions

Chapter 22Code Design Tips

Next: 22.4 Be Wary of Modules Without Any Parameters

22.3 Take Full Advantage of Local Modularization

A local module is a procedure or function that is defined within the declaration section of another module The scope of a local module is the module in which it is declared It is invisible to all other modules, and can be called only from within that defining module

Few PL/SQL developers are aware of the local module feature, and fewer yet take full advantage of this capability Yet I can think of few other aspects of the language that are more important to

constructing clean, elegant, easily maintained programs I strongly encourage you to use local

modules at every possible opportunity, and offer several examples in this section to highlight their usefulness

Local modules are very handy ways to "normalize" redundant code inside a program If you perform the same calculation over and over again in a module, don't hardcode the calculation repeatedly Instead, place it in its own function or procedure and then call that module The power of such an approach is clear when you examine the following program In the format_data procedure, I extract a value from the rg_sales record group, divide it by projected sales, and convert to a formatted string over and over again This code is taken from a production Oracle Forms application, and is actually just a small portion of the full set of more than two dozen repetitive calculations

Trang 23

Recorder or some other utility to automate the process However you manage it, though, you still end

up with lots of repetitions of the same fragment of code You still end up with code that is hard to maintain

Because I have exposed the way I perform the calculation, I must upgrade each distinct calculation whenever a change is required (different numeric format, different numeric formula, etc.) If, on the other hand, I hide the calculation behind the interface of a callable module, then the calculation is coded only once With the help of a local module, the format_data procedure is transformed as shown

Trang 24

a change to the npv function and then recompile No fuss, no muss

Notice that it doesn't make any sense to create npv as a standalone module outside of the format_data procedure This calculation is very specific to the format_data program Because no other module would ever call it, you needn't clutter up your stored procedure environment or your Oracle Forms program unit listing with this module-specific utility

I have found that few developers are aware of the ability to create local modules I have also found that these modules-within-a-module play an important role in allowing me to write well-structured, elegant programs

These days it seems that whenever I write a program with more than 20 lines, and with any

complexity whatsoever, I end up creating several local modules It helps me see my way through to a solution in the following ways:

● Conceptualizing my code at a higher level of abstraction by assigning a name to a whole

sequence of statements

● Performing top-down design and step-wise refinement of my requirements

● Extracting local modules at a later date, thus making truly independent, reusable procedures or functions if the need arises

Take a look at any of your more complex programs and I guarantee you will quickly identify

segments of the code that would serve you better bundled into a local module

Previous: 22.2 Build the

Most Functional Functions

Oracle PL/SQL Programming, 2nd Edition

Next: 22.4 Be Wary of Modules Without Any Parameters

22.2 Build the Most

Functional Functions

Book Index 22.4 Be Wary of Modules

Without Any Parameters

The Oracle Library

Navigation

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

Trang 25

Previous: 22.3 Take Full

Advantage of Local

Modularization

Chapter 22Code Design Tips

Next: 22.5 Create Independent Modules

22.4 Be Wary of Modules Without Any Parameters

While you certainly shouldn't create parameters where you don't need them, I have found that a lack

of parameters in a module usually reflects a limited vision of how the module will be used That limited vision generally translates directly to a limited use of the module.[1]

[1] Very few modules truly have no input or output Two examples of appropriate

parameterless modules are a procedure that simply encapsulates a sequence of

statements and a procedure that manipulates global variables Such programs are the

exception rather than the rule

In many of the cases, modules without parameter lists are fundamentally crippled they force a programmer to know about the internals of the module and therefore cannot act as true black boxes This situation arises most often from an overreliance on global variables

Consider the example of the parameterless company_name function shown here This program is driven by an Oracle Forms global variable It returns the name of the company corresponding to the company ID number in the global

FUNCTION company_name RETURN VARCHAR2

IS

cname company.company_id%TYPE;

BEGIN

SELECT name INTO cname FROM company

WHERE company_id = :GLOBAL.company_id;

RETURN cname;

EXCEPTION

WHEN NO_DATA_FOUND THEN RETURN NULL;

END;

This function works just fine, as long as I make sure that I have set the global variable to the

appropriate company ID before I call the function If I look only at the function's specification:

Ngày đăng: 20/10/2013, 11:15

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN