Tải bản đầy đủ
11 Don't Forget Backward Compatibility

11 Don't Forget Backward Compatibility

Tải bản đầy đủ

Chapter 3
The PL/SQL Development
Spiral

3.12 Obliterating the Literals
There are still two things that bother me about the repeated function: first, the function is not defined in a
package and, second, a user of repeated has to know the correct literals to pass to it to get the right kind of
conversion action. On general principles, I believe that everything built in PL/SQL should be placed inside a
package. This construct is the cornerstone of programming in the PL/SQL language and offers many
advantages, explored in detail throughout this book. My second concern about literals can be answered by
creating a package −− so I will show you how to convert the standalone repeated function into a package.
I do not believe that a user of my code should have to remember the specific characters to pass in a string
literal. Is it UL or BS? Is it n for "no action" or l for "leave alone"? With the function as implemented
throughout this chapter, there is no way for a developer to know at compile time if she called repeated
properly.
Beyond this difficulty, applications the world over would be much better off if their creators avoided the use
of hard−coded literals in their code. Every time the repeated function is called, some string literal is being
hard−coded into a program. If the repeated function is ever modified to expand the scope of action and
different literals are used, all those other programs could go haywire. A much better approach would provide
named constants in place of the hard−coded strings so that (a) at compile time a developer would know if the
call to the function is correct and (b) the actual string values for the action codes can be hidden from view −−
and changed as often as is necessary.
The best way (really, the only way) to create named constants for use throughout a PL/SQL application is to
put these constants −− and the code with which they are used −− into a package. The stg package shown in
Example 3.11 offers the same functionality as the repeated function, with the additional benefit of named
constants. Now instead of having a standalone repeated function, I have a dup function in the stg package, and
the following constants:
stg.ul
Indicates that you want UPPER−lower case conversion
stg.lu
Indicates that you want lower−UPPER case conversion
stg.n
Indicates that you do not want any case conversion
So when I want to duplicate or repeat the string "abc" 10 times with UPPER−lower conversion, I would
execute this statement:
stg.dup ('abc', stg.ul, 10);

By referencing the stg.ul constant, I can verify at compile time that I am using a valid action code for case
conversion.

145

[Appendix A] Appendix: PL/SQL Exercises
Notice that I have placed the dup function within a very generic string package. I do this to anticipate future
requirements for string processing. By creating this package, I have established a repository in which I can
place other, related functions and procedures as I think of them. All will be called with the "stg" prefix,
indicating that they are oriented to string processing.
Example 3.11: A Duplicate String Package
CREATE OR REPLACE PACKAGE stg
IS
lu CONSTANT VARCHAR2(1) := 'A';
ul CONSTANT VARCHAR2(1) := 'B';
n CONSTANT VARCHAR2(1) := 'X';
FUNCTION dup
(stg_in IN VARCHAR2,
action_in IN VARCHAR2 := n,
num_in IN INTEGER := 1)
RETURN VARCHAR2;
END stg;
/
CREATE OR REPLACE PACKAGE BODY stg
IS
FUNCTION dup
(string_in IN VARCHAR2,
action_in IN VARCHAR2 DEFAULT n,
num_in IN INTEGER := 1)
RETURN VARCHAR2
IS
v_action VARCHAR2(10) := UPPER (action_in);
initval VARCHAR2(32767);
nextval VARCHAR2(32767);
v_retval VARCHAR2(32767);
BEGIN
assert
(v_action IN (lu, ul, n),
'Please use the package constants: ul, lu or n');
assert
(num_in >= 0, 'Duplication count must be at least 0.');
IF v_action = ul
THEN
initval := UPPER (string_in);
nextval := LOWER (string_in);
ELSIF v_action = lu
THEN
initval := LOWER (string_in);
nextval := UPPER (string_in);
ELSE
initval := string_in;
nextval := string_in;
END IF;
v_retval :=
RPAD (initval, LENGTH (string_in) * (num_in+1), nextval);
RETURN v_retval;
END dup;
END stg;
/

3.12 Obliterating the Literals

146

[Appendix A] Appendix: PL/SQL Exercises
3.11 Don't Forget
Backward Compatibility

3.13 Glancing Backward,
Looking Upward

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

3.12 Obliterating the Literals

147

Chapter 3
The PL/SQL Development
Spiral

3.13 Glancing Backward, Looking Upward
Now that was a journey through the valleys and peaks of modularization! I started with a simple solution to
what seemed to be a very simple request. I ended up with a very generic, well−structured function that
handles the simple request and many others as well.
Along the way, I applied many best practices of recommendations for module construction (some of which
are covered in Chapter 2, Best Practices for Packages, some of which are discussed in Oracle PL/SQL
Programming). With each successive change to twice (and then repeated), I took another turn up along the
spiral that represents the rise in quality of my PL/SQL coding techniques. At the end, I had a polished
function with proven performance and wide applicability. Take a look at the final version of my repeater
function (the dup package). Could you have ever predicted that endpoint from the first version of the twice
function? I certainly could not have. In fact, when I started this chapter, the repeated function looked quite
different from the way it does now. I found many improvements to make from my first progression of twice (a
thorough improvisation performed "live" during a class in Tulsa, Oklahoma) as I "rationalized" the code into
an chapter.
And so we come face to face with one of the most extraordinary characteristics of the programming spiral. It's
not like a Slinky. That toy has the right shape, but it also has a beginning and an end. The spiral for developers
has a beginning (though you would probably have to make an arbitrary choice to locate it), but it certainly has
no end. You can always find ways to improve your code, your coding philosophy, and your quality of
programming life.
So the next time you sit down to write a program, don't settle for "getting the job done." Instead, push yourself
up that spiral towards excellence.

3.12 Obliterating the
Literals

II. PL/Vision Overview

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

148

Chapter 4

149

4. Getting Started with PL/Vision
Contents:
What Is PL/Vision?
PL/Vision Package Bundles
Installation Instructions
Installing Online Help for PL/Vision
Using Online Help
Summary of Files on Disk

4.1 What Is PL/Vision?
As I've mentioned in earlier chapters, PL/Vision is a collection of PL/SQL packages and supporting
SQL*Plus scripts that can change radically the way you develop applications with the PL/SQL language. This
chapter describes the product in greater detail, lists the packages included in it, and provides instructions for
installing the PL/Vision Lite Online Reference provided on the companion disk.

4.1.1 The Benefits of PL/Vision
What can PL/Vision do for you? The possibilities are almost endless:

Improve your productivity. PL/Vision goes a long way towards helping you avoid reinventing the
wheel. Need to change a long string into a word−wrapped paragraph? Use the PLVprs.wra procedure.
Want to display the contents of a PL/SQL table? Call the PLVtab.display procedure. Need to log
activity to the database or maybe even write your information to a PL/SQL table? Call the
PLVlog.put_line program. By using PL/Vision, you write much less code yourself, and instead
spend your time deciding which prebuilt components of PL/Vision to plug into your own applications.
You are able to focus much more of your effort on implementing the business rules for your systems.

Decrease the number of bugs in your code and fix the bugs you do find more rapidly. Since you will
be writing less code, you will minimize the opportunities for bugs to creep into your own programs.
When you do have compile errors, you can call the PLVvu.err program to show you precisely where
the error occurred in your program. Furthermore, PL/Vision packages offer many ways to trace the
actions taken within those packages. When you need more information, you simply call the
appropriate package toggle to turn on a trace and then run your test. When you are done testing and
debugging, you turn off the trace mechanisms and put your application into production.

Help you develop and enforce coding standards and best practices. You will do this in two ways:
first, by using packages that explicitly support coding standards, such as PLVgen; second, by
examining the code behind PL/Vision. This PL/SQL library has provided numerous opportunities for
me to put my own best practices for packages into action. You will, no doubt, find occasional
violations of my best practices, but by and large the code in PL/Vision should provide a wealth of
ideas and examples for your own development.

Increase the percentage of reusable code in your applications. The more you leverage PL/Vision, the
fewer new programs you have to write yourself. And this advantage doesn't just accrue to individual
developers. You can use PL/Vision across multiple applications −− it can be part of a truly
enterprise−wide object and module library.

4. Getting Started with PL/Vision

150

[Appendix A] Appendix: PL/SQL Exercises
Demonstrate how to modularize and build layers. I don't want you to simply use PL/Vision. I want
you to learn how and why I built PL/Vision so that you can accomplish the same kind of development
yourself. We all need to be fanatically devoted to modularizing code for maximum reusability. We all
need to become sensitive to identifying program functionality that should be broken out into different
layers. To some extent, you can develop such sensitivity only by practicing the craft of software
construction. But you can also examine closely the work of others and learn from their example (both
the good and the bad).

Inspire you to be creative, to take risks in your coding. I have found that the real joy of programming
is to be found in trying out new ways of doing things. When you stretch boundaries −− whether they
are the boundaries of your own experience or those of the documented features of a language −− you
make discoveries. And when those discoveries turn out to be productive, you create new things.

4.1.2 The Origins of PL/Vision
PL/Vision has both top−down and bottom−up origins. Many of the pieces of PL/Vision were pulled together
after the fact; I would come up with an interesting package, then draw it into the embrace of PL/Vision. After
incorporating it I would reexamine other packages in PL/Vision to see how I could leverage this latest
addition. I consider that the bottom−up approach.
PL/Vision as a coherent library of interlocking packages first sprang out of a recognition of the need to break
up a single large program into multiple layers of code. In the fall of 1995 I became obsessed with the idea of
writing a program that would "pretty−print" or reformat PL/SQL source code to follow my suggested coding
style. It would read the code from the ALL_SOURCE data dictionary view and perform such tasks as
upper−case all keywords and apply consistent indentation and line breaks to the code. I worked feverishly
after hours on this project for a week and found myself with a working prototype: the psformat procedure. It
was an exciting week for me. I could feed psformat (which ran to almost 1000 lines of text) the code for a
procedure stuffed into one long, unformatted string and retrieve from it a nicely formatted PL/SQL program
unit.
I was careful not to write a parser for the PL/SQL language. I didn't think such a step was necessary to handle
my limited scope and I sure didn't want to spend the time required for such a task. Yet I found (as many of
you would probably anticipate) that psformat didn't handle all the nuances of PL/SQL code correctly. So I
would dive back in and tinker with it just a little bit more so that it would understand this or that element of
the language.
Two weeks later, I had completely reimplemented psformat three times. With each implementation I came
closer to handling the conversion and formatting of a wide range of PL/SQL program syntax. At the same
time, my one big program grew that much bigger and more convoluted. I was just so taken up in
implementing my obsession that I did not feel that I had the time to modularize my code. And each time I
came that much closer to cobbling together a parser for PL/SQL.
After round three and too little sleep, I began to realize that I would probably never meet my objectives taking
this piecemeal approach. Painfully and reluctantly, I gave up on this program (as you will see, PL/Vision does
not provide a program to automatically indent and line−break your code). I did not, however, abandon all the
code I had developed. Instead, I set my sights on a more limited and achievable goal: a program that would
convert the case of source code to follow the UPPER−lower method. I would leave the format of the code as
is, but change all keywords to upper−case and all application−specific identifiers to lower−case.
In the process of enhancing psformat, I had constructed a table that contained the keywords for the PL/SQL
language and information about how those keywords affected the format of the source code (this is now the
PLV_token table). I also recognized that I wanted to be able to read the original code from any number of
different sources and write the converted code to any number of different targets.
4.1.2 The Origins of PL/Vision

151

[Appendix A] Appendix: PL/SQL Exercises
At the same time that I shifted my expectations and goal, I forced myself to take the time to break up my
monster procedure and employ top−down design to straighten out my logic. Thus was PL/Vision born.
Directly out of this process, I created a single PLVtext package to manipulate PL/SQL source text. This single
package eventually transformed itself into PLVio, PLVobj, and PLVfile to handle very generically a variety
of source and target repositories for PL/SQL source code. I separated out many string−parsing tasks from
psformat into PLVprs, which over time broadened into PLVprs, PLVlex, PLVtkn, and, finally, PLVprsps.
When all of my layering and partitioning was done, I got back to building the PLVcase package to perform
the actual case conversion. My monstrous single procedure became a very small, relatively simple package.
As I broke out these different aspects of PL/SQL functionality, I began to see the outlines of a whole
substantially larger than the sum of its parts: a very generic and highly reusable toolbox that could be used in
any PL/SQL−based development environment. From that point on, I was on the lookout for any utility or
package I had built or would build that could add to the scope and functionality of PL/Vision.
Throughout this development process, I found myself learning more and more about what was really involved
in building packages and leveraging reusable code. My conception of a set of best practices for packages also
crystallized.
My desire to share what I had learned and built grew with the number of packages in PL/Vision. Finally, I
realized that the best way to make the most of my knowledge was to write a book centered around the code
and lessons of PL/Vision. I hope that you will find the software and the accompanying text useful.

II. PL/Vision Overview

4.2 PL/Vision Package
Bundles

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

4.1.2 The Origins of PL/Vision

152

Chapter 4
Getting Started with
PL/Vision

4.2 PL/Vision Package Bundles
PL/Vision Lite consists of 32 PL/SQL packages. From a conceptual standpoint, the various packages are
grouped into three bundles: building blocks, developer utilities, and plug−and−play components. These
packages in each of these bundles are summarized in the following sections. Chapter 5, PL/Vision Package
Specifications, contains a full summary of all package specifications.
NOTE: Some of the packages listed in the following tables are not described in detail in this
book. In cases in which neither the package conception nor its implementation offered any
additional insights that would help you build your own packages, I elected to omit the
discussion from the book. For more details about these packages (indicated by * in the
tables), see the PL/Vision Online Reference on the companion disk.

4.2.1 Building Blocks
The building block packages provide low−level functionality upon which other packages in PL/Vision are
built. You can, of course, also use these building blocks to construct your own applications. Examples of
building block packages include an interface to PL/SQL tables, string parsers, a file I/O manager, and a
message handling mechanism.

Table 4.1: PL/Vision Building Block Packages
Package

Description

p

Offers a feature−rich and minimal−typing substitute for the DBMS_OUTPUT package.

PLV

Top−level package for PL/Vision. Contains constants and generic utilities for use throughout the
library.

PLVchr

Provides information about single characters in a string. You can display the ASCII codes for
characters in a string and perform other operations relating to individual characters.*

PLVfile

Manages operating system file I/O. PLVfile provides a layer of code around the UTL_FILE
builtin package and offers some very high−level capabilities, such as a file copy. Use this
package only if you are using Oracle Server Release 7.3 and above.

PLVio

Generalized input/output package used to both read from and write to repositories for PL/SQL
source code. For example, you can use PLVio, via the PLVcase package, to read a program from
its operating system file, convert keywords to upper−case, and then store it in the database.

PLVlex

Lexical analysis and parsing package. Recognizes lexical elements of the PL/SQL language and
can be used to read one PL/SQL identifier at a time.*

PLVlst

Generic list manager for PL/SQL that's built on PL/SQL tables. Following the specification of the
LIST package of Oracle Developer/2000, this package provides a comprehensive interface to lists
in PL/SQL.*
153

[Appendix A] Appendix: PL/SQL Exercises
PLVmsg Stores standard messages for use in an application. Use this package to consolidate all different
kinds of message text with which you can associate a number (such as error number). You can
also use PLVmsg to override standard Oracle error messages with your, more
application−specific information.
PLVobj

Programmatic interface to the ALL_OBJECTS data dictionary view. This package encapsulates
logic for specifying and reading source code for a given object. It provides an excellent model for
building a package around a view or cursor. PLVobj even implements a kind of dynamic cursor
FOR loop through a procedure with the loopexec program.

PLVprs

Performs string parsing actions. This is the most generic of the string manipulation packages of
PL/Vision.

PLVprsps Parses PL/SQL source code. You can parse a single string or an entire program unit. The parsed
tokens are placed in a PL/SQL table, which can then be used as the basis for further analysis or
conversion of the code.
PLVstk

Generic stack manager package, built on PLVlst. Provides a full set of operations for both FIFO
(first−in−first−out) queues and LIFO (last−in−first−out) stacks.*

PLVtab

Provides an interface to predefined PL/SQL table structures. Also allows you to easily and
flexibly display the contents of PL/SQL tables.

PLVtkn

Package interface to the PLV_token table, which contains information about tokens, particularly
keywords, in the PL/SQL language. Use PLVtkn to determine if an identifier is a keyword or a
reserved word, and even the type of keyword (syntax, builtin, symbol, etc.).

4.2.2 Developer Utilities
The developer utilities of PL/Vision are self−contained utilities that you can use to improve your development
environment. Examples of building block packages include a PL/SQL code generator and an online help
delivery mechanism for PL/SQL programs.

Table 4.2: PL/Vision Developer Utility Packages
Package Description
PLVcase Converts the case of PL/SQL code to the UPPER−lower method. You can convert a single token,
a line, a program, or a set of programs.
PLVcat

Catalogues the contents of PL/SQL code, placing the results in one of two database tables. You
can either catalogue the list of elements referenced by a particular program (the PLVrfrnc table) or
the list of elements defined in the specification of a package (the PLVctlg table).

PLVddd Dumps Data Definition Language (DDL) syntax from a particular schema. Allows you to recreate
database objects easily in other schemas. You can also use output from PLVddd to compare data
structures between schemas or analyze changes over time.*
PLVgen Generates PL/SQL program units and SQL*Plus scripts. This package can greatly improve
developer productivity, adherence to coding standards and best practices, and the overall quality of
code produced.
PLVhlp Provides an architecture by which developers can provide online help for their PL/SQL programs
to their (developer) users. Using this package, you can make comment text in your source code
available in a structured way to users of your code.
PLVtmr Allows you to measure elapsed time of PL/SQL code down to the hundredth of a second. This
package offers a programmatic layer around the GET_TIME function of the builtin
DBMS_UTILITY package.
4.2.2 Developer Utilities

154

[Appendix A] Appendix: PL/SQL Exercises
PLVvu

Multifaceted view package. Shows you the errors in a stored object compile, or specified lines of
source code from the data dictionary, etc. Offers a convenient substitute for the SHOW ERRORS
command of SQL*Plus.

4.2.3 Plug−and−Play Components
The most advanced packages in PL/Vision are the plug−and−play components. These packages allow
developers to replace whole sections of code with programs from PL/Vision packages. In essence, you plug in
PL/Vision code and immediately gain benefits in your application, employing a declarative style of
programming in a procedural language. The best example of a PL/Vision plug−and−play component is
PLVexc, which provides very high−level exception handling programs.

Table 4.3: PL/Vision's Plug−and−Play Packages
Package

Description

PLVcmt

Offers a programmatic interface to the execution of commits, rollbacks, and the setting of
savepoints. Gives you more flexibility than calling the corresponding builtins. You can, for
example, opt to turn off commits in your application without changing any of your code.

PLVdyn

Offers a high−level interface to the DBMS_SQL builtin package. You can perform many
complex operations with a call to a single PLVdyn program. This package is strongly
recommended over direct use of the DBMS_SQL builtin packages.

PLVdyn1 Built upon PLVdyn, this package encapsulates dynamic SQL operations that require single bind
variables (PLVdyn does not work with any bind variables).
PLVexc

Generic exception−handling package. Instead of writing your own exception handlers, just call
one of the PLVexc prebuilt, high−level handlers. Your errors will be displayed or written to the
PL/Vision log, as you specify.

PLVfk

Provides foreign key management, including a single function to perform lookups of foreign keys
for any table and any structure. This package can greatly reduce the volume of code you have to
write to manage foreign keys. The dynamic SQL in PLVfk works surprisingly quickly.

PLVlog

This package provides a generic logging facility for PL/Vision−based applications. With PLVlog,
you can write information to a database table, PL/SQL table, operating system file (for PL/SQL
Release 2.3 and above), or standard output.

PLVrb

Provides a programmatic interface to rollback and savepoint processing. Allows you to specify
savepoints by variable, instead of hard−coding identifiers in your code. You can also opt to turn
off rollbacks in your application without changing any of your code.

PLVtrc

Provides an execution trace for PL/SQL programs. Mirrors the overloading of the p package to
allow you to show different kinds of data. Offers startup and terminate procedures that
allows PLVtrc to maintain its own execution call stack.

4.1 What Is PL/Vision?

4.3 Installation Instructions

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

4.2.3 Plug−and−Play Components

155