Tải bản đầy đủ
p: A Powerful Substitute for DBMS_OUTPUT

p: A Powerful Substitute for DBMS_OUTPUT

Tải bản đầy đủ

[Appendix A] Appendix: PL/SQL Exercises
Set the line separator. This character gives you a way to preserve white space (blank lines) in your
source.

Control p.l output. The show override argument in the p.l procedure gives you some added
flexibility over when p.l will actually show you something.

7.1 Using the l Procedure
The p.l procedure is a pleasure to use. When you call p.l instead of the DBMS_OUTPUT.PUT_LINE
procedure, you will never have to worry about raising the VALUE_ERROR exception. You can display
values of up to 32,767 bytes! You can pass many different kinds of data to the l procedure and it will figure
out what to do and how to best display the information.
What, you worry? No, you let the package do the worrying for you. You get to concentrate on building your
application.
You use p.l just as you would its builtin cousin, except that the p package offers a much wider overloading
for different types and combinations of types of data. You pass it one or more values for display purposes.
You can also use the final argument of the p.l procedure to control when output should be displayed (see
Section 7.4, "Controlling Output from p").
Here are the headers for the version of p.l that display a number and a string−date combination, respectively.
PROCEDURE l (number_in IN NUMBER, show_in IN BOOLEAN := FALSE);
PROCEDURE l
(char_in IN VARCHAR2, date_in IN DATE,
mask_in IN VARCHAR2 := PLV.datemask,
show_in IN BOOLEAN := FALSE);

To view the salary of an employee, you simply execute:
p.l (emp_rec.sal);

To view the employee name and hire date, you execute:
p.l (emp_rec.ename, emp_rec.hiredate)

and you will see this data in this format:
JONES: May 12, 1981 22:45:47

To get the same information using the default functionality of DBMS_OUTPUT, you would have to enter
something as ugly and time−consuming as this:
DBMS_OUTPUT.PUT_LINE (emp_rec.ename || ': ' ||
TO_CHAR (emp_rec.hiredate, 'FMMonth DD, YYYY HH:MI:SS'))

Which would you rather type? That should give you a good sense of the potential productivity gains available
through p![2]
[2] Did you ever notice how old the data in the emp table is? Oracle Corporation should
update that demonstration table to reflect corporate growth and increased salaries...but I guess
they have to worry about backward compatibility of demonstration scripts!

7.1 Using the l Procedure

267

[Appendix A] Appendix: PL/SQL Exercises

7.1.1 Valid Data Combinations for p.l
Table 7.1 shows the different types of data that can be passed to the p.l procedure.
See the p package specification (or the table in Chapter 5, PL/Vision Package Specifications) for the headers
of all the corresponding versions of the l procedure.

Table 7.1: Valid Data Combinations for p.l
Data Combinations

Resulting Value

VARCHAR2

The string as supplied by the user.

DATE

The date converted to a string, using the specified date mask. The default date
mask is provided by PLV.datemask −− a PL/Vision−wide setting.

NUMBER

The number converted to a string using the default format mask.

BOOLEAN

The string "TRUE" if the Boolean expression evaluates to TRUE, "FALSE" if
FALSE, and the NULL substitution value if NULL.

VARCHAR2, DATE

The string concatenated to a colon, concatenated to the date (converted to a
string as explained above).

VARCHAR2, NUMBER

The string concatenated to a colon, concatenated to the number (converted to a
string as explained above).

VARCHAR2, BOOLEAN The string concatenated to a colon, concatenated to the Boolean (converted to a
string as explained above).

7.1.2 Displaying Dates
When you display a date using p.l, it uses the string returned by the PLV.datemask function as the format
mask. The default value of the format mask is:
The DBMS_OUTPUT Package
The DBMS_OUTPUT package allows you to display information to your session's output device from within
your PL/SQL program. As such, it serves as just about the only easily accessible means of debugging your
PL/SQL Version 2 programs. DBMS_OUTPUT is also the package you will use to generate reports from
PL/SQL scripts run in SQL*Plus.
Theoretically, you write information to the DBMS_OUTPUT buffer with calls to PUT_LINE and PUT and
then extract that information for display with the GET_LINE program. In reality (in SQL*Plus, anyway), you
simply call the PUT_LINE program from within your PL/SQL program and when your program finishes
executing, all the text "put" to the buffer is displayed on your screen. The following SQL*Plus session gives
you an idea of what you must type:
SQL> exec DBMS_OUTPUT.PUT_LINE ('this is great!');
this is great

The size of the DBMS_OUTPUT buffer can be set to a size between 2,000 bytes (the default) and 1,000,000
bytes with the ENABLE procedure. If you do not ENABLE the package, then no information will be
displayed or will be retrievable from the buffer.
When using DBMS_OUTPUT in SQL*Plus, you can use the SET command to enable output from
DBMS_OUTPUT and also set the size of the buffer. To enable output, you must issue this command:
7.1.1 Valid Data Combinations for p.l

268

[Appendix A] Appendix: PL/SQL Exercises
SQL> set serveroutput on

To set the buffer size to a value other than 2,000, add the size clause as follows:
SQL> set serveroutput on size 1000000

I recommend that you put the SET SERVEROUTPUT command in your login.sql script so your session
is automatically enabled for output. Remember, however, that every time you reconnect inside SQL*Plus, all
of your package variables are reinitialized. So if you issue a CONNECT command in SQL*Plus, you will
need to reenable DBMS_OUTPUT. The script ssoo.sql (on the disk) does this for you with a minimum of
fuss. To enable output and set the buffer to its maximize size (1 megabyte), simply type:
SQL> @ssoo

See Chapter 15 of Oracle PL/SQL Programming, for more details on DBMS_OUTPUT.
'FMMonth DD, YYYY FMHH24:MI:SS'

If you would like to change the format used to display dates, you can either specify a new format when you
call p.l or you can change the default mask maintained by the PLV package.
To specify a different format in the call to p.l, simply include the mask string after the date argument. Here,
for example, is the header for the version of p.l that displays a date:
PROCEDURE l
(date_in IN DATE,
mask_in IN VARCHAR2 := PLV.datemask,
show_in IN BOOLEAN := FALSE);

So to display the name of an employee and the month/year she was hired, I can use:
p.l (emp_rec.ename, emp_rec.hiredate, 'Month YYYY');

Alternatively, I can set the default format for any date displayed in PLV with this call:
PLV.set_datemask ('Month YYYY');

and then the call to p.l could be simplified to:
p.l (emp_rec.ename, emp_rec.hiredate);

6.6 The Predefined
Constants

7.2 The Line Separator

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

7.1.1 Valid Data Combinations for p.l

269

Chapter 7
p: A Powerful Substitute
for DBMS_OUTPUT

7.2 The Line Separator
When you compile and store code in SQL*Plus, any blank lines in your source code are discarded. This
annoying "undocumented feature" wreaks havoc at compile time. If there are any compile errors, the line
number stored in USER_ERRORS and returned by SHOW ERRORS almost never matches the line number
of the code in your operating system file. What an annoyance!
The situation gets even worse when you really want to preserve those blank lines for readability. The PLVhlp
package, for example, provides an architecture for online help. Without blank lines in the help text, it would
be very difficult to make this text understandable. It would be awfully nice to be able to preserve those blank
lines −− or at least make a line appear to be blank when displayed.
The p package recognizes this need and allows you to specify a line separator character. If a line of text
passed to p.l consists only of the line separator character, it is displayed as a blank line.
You set the line separator with the set_linesep procedure, whose header is:
PROCEDURE set_linesep (linesep_in IN VARCHAR2);

You can retrieve the current line separator character with the linesep function:
FUNCTION linesep RETURN VARCHAR2;

The default line separator character is =. As a result, if I execute the following anonymous block,
BEGIN
p.l
p.l
p.l
p.l
p.l
END;
/

('this');
('=');
('is');
('=');
('separated!');

I see this output:
this
is
separated!

7.1 Using the l Procedure

7.3 The Output Prefix

270

[Appendix A] Appendix: PL/SQL Exercises
Copyright (c) 2000 O'Reilly Associates. All rights reserved.

271

Chapter 7
p: A Powerful Substitute
for DBMS_OUTPUT

7.3 The Output Prefix
PL/Vision works extensively with stored PL/SQL code −− which often has (and should have) lots of
indentation to reveal the logical flow of the program. If I use the native, builtin PUT_LINE procedure to
display this text, it comes out left−justified; all leading spaces are automatically trimmed by the
DBMS_OUTPUT.PUT_LINE builtin. This is not a very useful way to display code.
The p package handles this situation by prefixing all text with a prefix string. As long as the prefix string is
not composed entirely of spaces, the leading spaces in your own text will be preserved.
You can set and retrieve the value of the prefix string with these two programs:
PROCEDURE set_prefix (prefix_in IN VARCHAR2 := c_prefix);
FUNCTON prefix RETURN VARCHAR2;

The default prefix (stored in the package constant c_prefix) is CHR(8), which is the backspace character.
This character, like many of the other nonprinting characters in the ASCII code table, displays as a black box
in the Windows environment and functions well as a prefix.
You may wish to substitute a different value more appropriate to your operating system. To do this, simply
call the set_prefix procedure as shown in the example below:
SQL> exec p.set_prefix ('*');
SQL> exec p.l (SYSDATE);
*May 12, 1996 22:36:55

If you call set_prefix, but do not pass a value, you will set the prefix back to its default.

7.2 The Line Separator

7.4 Controlling Output
from p

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

272

Chapter 7
p: A Powerful Substitute
for DBMS_OUTPUT

7.4 Controlling Output from p
The p package offers more flexibility than does DBMS_OUTPUT in determining when output should, in fact,
be displayed. With DBMS_OUTPUT, you face an all or nothing scenario. If output has been enabled, you see
all information passed to PUT_LINE. If you have not (in SQL*Plus) executed the verbose SET
SERVEROUTPUT ON command, nothing appears on the screen.
With p.l, you can match this functionality and then go a bit beyond it as well. The p package provides a
toggle to determine whether calls to p.l should generate output. The programs that make up this toggle are:
PROCEDURE turn_on;
PROCEDURE turn_off;

If you call turn_off to disable output from p.l, nothing will be displayed −− unless you explicitly
request that the information be shown. The last parameter of every overloading of the l procedure is the
"show override". If you pass TRUE, the information will always be displayed (assuming that output from
DBMS_OUTPUT has been enabled). The default value for the "show override" is FALSE, meaning "do not
override."
In the following sequence of calls in SQL*Plus, I manipulate the status of output in the p package to
demonstrate how the show override argument can be used.
SQL> exec p.turn_off
SQL> exec p.l (SYSDATE);
SQL> exec p.l (SYSDATE, show_in => TRUE);
*May 12, 1996 22:43:51
SQL> exec p.l (SYSDATE IS NOT NULL, show_in => TRUE);
*TRUE
SQL> exec p.turn_on
SQL> exec p.l(SYSDATE);
*May 12, 1996 22:45:47

The p package could, of course, offer much more flexibility even than this variation of all or nothing. Many
developers have implemented variations on this package with numeric levels that provide a much finer
granularity of choice over which statements will actually display output. Given the nearness of third−party
(and Oracle−supplied) debuggers for PL/SQL, however, I exercised self−restraint and focused my efforts in
the p package on ease of use and developer productivity.
Special Notes on p
Here are some factors to consider when working with the p package:

The prefix, line separator, and NULL substitution values can be up to 10 characters in length.


273

[Appendix A] Appendix: PL/SQL Exercises
When you turn_on output from the p package, the DBMS_OUTPUT.ENABLE procedure is called
with a maximum size buffer of 1 megabyte.

Any string that is longer than 80 characters in length will be displayed in a paragraph−wrapped
format at a line length of 75 characters.

The p package will only send information to standard output. If you want to send text to a database
table or PL/SQL table or other repository, you might consider using PLVlog or even PLVio if the text
has to do with PL/SQL source code.

The biggest challenge in implementing the p package was to modularize the code inside the package
body so that all those overloadings of the l procedure do not result in chaos. I needed to avoid
redundant code so that I could easily add to the overloadings as the need arose and even add new
functionality to the package's display options (such as paragraph−wrapping long text, a rather recent
enhancement). I accomplished this by creating a private module, display_line, which is called
by each of the p.l procedures.

The current set of overloadings of p.l is really quite minimal. You might want to try your hand at
enhancing PL/Vision yourself by increasing the variety of datatypes one can pass to the l procedure.
What about two numbers or a number and a date? Give it a try!

7.3 The Output Prefix

8. PLVtab: Easy Access to
PL/SQL Tables

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

274

Chapter 8

275

8. PLVtab: Easy Access to PL/SQL Tables
Contents:
Using PLVtab−Based PL/SQL Table Types
Displaying PLVtab Tables
Showing Header Toggle
Showing Row Number Toggle
Setting the Display Prefix
Emptying Tables with PLVtab
Implementing PLVtab.display
The PLVtab (PL/Vision TABle) package offers predefined PL/SQL table types and programs to make it easier
to declare, use, and display the contents of PL/SQL tables. PL/SQL tables are the closest things to arrays in
PL/SQL, but there are a number of complications. First, to use a PL/SQL table, you first have to declare a
table type. Then you can declare and use the PL/SQL table itself. Beyond the definition of the PL/SQL table,
the fact that it is a sparse, unbounded, homogeneous data structure can lead to complications, particularly
when it comes to scanning and displaying those structures (see Chapter 10 of Oracle PL/SQL Programming).
By using PLVtab, you can avoid (in most cases) having to define your own PL/SQL table types. You can also
take advantage of flexible, powerful display procedures to view table contents.
When you display the contents of PL/SQL tables, PLVtab allows you to:

Show or suppress a header for the table

Show or suppress the row numbers for the table values

Display a prefix before each row of the table
This chapter shows how to use the different aspects of PLVtab.

8.1 Using PLVtab−Based PL/SQL Table Types
When you use PL/SQL tables, you normally perform a number of common actions, including defining the
table type, declaring the table, filling up the rows, referencing the rows, and emptying the table when done.
When using a PLVtab−based table, you do not have to declare the table type. Instead you simply reference the
package−based type in your declaration. PLVtab predefines the following PL/SQL table TYPEs, shown in
Table 8.1:

Table 8.1: Table Types Predefined in PLVtab
Type

Description
boolean_table
PL/SQL

table of Booleans

date_table
PL/SQL

table of dates

integer_table
PL/SQL

table of integers

number_table
PL/SQL

table of numbers

8. PLVtab: Easy Access to PL/SQL Tables

276

[Appendix A] Appendix: PL/SQL Exercises
vc30_table
PL/SQL

table of VARCHAR2(30) strings

vc60_table
PL/SQL

table of VARCHAR2(60) strings

vc80_table
PL/SQL

table of VARCHAR2(80) strings

vc2000_table
PL/SQL

table of VARCHAR2(2000) strings

ident_table
PL/SQL

table of VARCHAR2(100) strings; matches PLV.plsql_identifier
declaration.

vcmax_table
PL/SQL

table of VARCHAR2(32767) strings
Let's compare the "native" and PL/Vision approaches to defining PL/SQL tables. In the following anonymous
block, I define a PL/SQL table of Booleans without the assistance of PLVtab.
DECLARE
TYPE bool_tabtype IS TABLE OF BOOLEAN
INDEX BY BINARY_INTEGER;
yesno_tab bool_tabtype;
BEGIN

With the PLVtab package in place, all I have to is the following:
DECLARE
yesno_tab PLVtab.boolean_table;
BEGIN

Once you have declared a table using PLVtab, you manipulate that table as you would a table based on your
own table TYPE statement.

7.4 Controlling Output
from p

8.2 Displaying PLVtab
Tables

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

8. PLVtab: Easy Access to PL/SQL Tables

277