Wednesday, March 19, 2008

Generating Output from PL/SQL Programs

Generating Output from PL/SQL Programs

The built-in packages offer a number of ways to generate output from within your PL/SQL program. While updating a database table is, of course, a form of "output" from PL/SQL, this chapter shows you how to use two packages that explicitly generate output. UTL_FILE reads and writes information in server-side files, and DBMS_OUTPUT displays information to your screen.

6.1 DBMS_OUTPUT: Displaying Output

DBMS_OUTPUT provides a mechanism for displaying information from your PL/SQL program on your screen (your session's output device, to be more specific). As such, it serves as just about the only immediately accessible (meaning "free with PL/SQL") means of debugging your PL/SQL stored code.[1] It is certainly your "lowest common denominator" debugger, similar to the used-and-abused MESSAGE built-in of Oracle Forms. DBMS_OUTPUT is also the package you are most likely to use to generate reports from PL/SQL scripts run in SQL*Plus.

[1] As this book is going to press, the following PL/SQL debuggers are now available: SQL-Station Debugger from Platinum Technology; SQL Navigator from Quest; Xpediter/SQL from Compuware; and Procedure Builder from Oracle Corporation.

Of all the built-in packages, the DBMS_OUTPUT package (and its PUT_LINE procedure, in particular) is likely to be the one you will find yourself using most frequently. You may therefore find it strange that I never call DBMS_OUTPUT.PUT_LINE. I find the design and functionality of DBMS_OUTPUT to be substandard and very frustrating.

In fact, I recommend that you never use this package -- at least, not directly. You should instead encapsulate calls to DBMS_OUTPUT (and the PUT_LINE procedure, in particular) inside a package of your own construction. This technique is discussed in the Section 6.1.6, "DBMS_OUTPUT Examples"" section later in this chapter.

6.1.1 Getting Started with DBMS_OUTPUT

The DBMS_OUTPUT package is created when the Oracle database is installed. The dbmsoutp.sql script (found in the built-in packages source code directory, as described in Chapter 1, Introduction) contains the source code for this package's specification. This script is called by the catproc.sql script, which is normally run immediately after database creation. The script creates the public synonym DBMS_OUTPUT for the package. Instance-wise access to this package is provided on installation, so no additional steps should be necessary in order to use DBMS_OUTPUT. As far as package usage is concerned, you will almost always be using only the DBMS_OUTPUT.PUT_LINE procedure and only in SQL*Plus. The section Section 6.1.2, "Enabling and Disabling Output"" later in this chapter shows how you set up DBMS_OUTPUT for use in SQL*Plus.

6.1.1.1 DBMS_OUTPUT programs

Table 6-1 shows the DBMS_OUTPUT program names and descriptions.


Table 6.1: DBMS_OUTPUT Programs

Name

Description

Use in SQL?

DISABLE

Disables output from the package; the DBMS_OUTPUT buffer will not be flushed to the screen

Yes

ENABLE

Enables output from the package

Yes

GET_LINE

Gets a single line from the buffer

Yes

GET_LINES

Gets specified number of lines from the buffer and passes them into a PL/SQL table

Yes

NEW_LINE

Inserts an end-of-line mark in the buffer

Yes

PUT

Puts information into the buffer

Yes

PUT_LINE

Puts information into the buffer and appends an end-of-line marker after that data

Yes

NOTE: All procedures in DBMS_OUTPUT have been enabled for indirect usage in SQL (that is, they can be called by a function that is then executed in a SQL statement), but only for Oracle 7.3 and later.

6.1.1.2 DBMS_OUTPUT concepts

Each user has a DBMS_OUTPUT buffer of up to 1,000,000 bytes in size. Write information to this buffer by calling the DBMS_OUTPUT.PUT and DBMS_OUTPUT.PUT_LINE programs. If you are using DBMS_OUTPUT from within SQL*Plus, this information will be displayed automatically when your program terminates. You can (optionally) explicitly retrieve information from the buffer with calls to DBMS_OUTPUT.GET and DBMS_OUTPUT.GET_LINE.

The DBMS_OUTPUT buffer can be set to a size between 2,000 and 1,000,000 bytes with the DBMS_OUTPUT.ENABLE procedure. If you do not enable the package, no information will be displayed or be retrievable from the buffer.

The buffer stores three different types of data -- VARCHAR2, NUMBER, and DATE -- in their internal representations. These types match the overloading available with the PUT and PUT_LINE procedures. Note that DBMS_OUTPUT does not support Boolean data in either its buffer or its overloading of the PUT procedures.

The following anonymous PL/SQL block uses DBMS_OUTPUT to display the name and salary of each employee in department 10:

DECLARE
CURSOR emp_cur
IS
SELECT ename, sal
FROM emp
WHERE deptno = 10
ORDER BY sal DESC;
BEGIN
FOR emp_rec IN emp_cur
LOOP
DBMS_OUTPUT.PUT_LINE
('Employee ' || emp_rec.ename || ' earns ' ||
TO_CHAR (emp_rec.sal) || ' dollars.');
END LOOP;
END;
/

This program generates the following output when executed in SQL*Plus:

Employee KING earns 5000 dollars.
Employee SCOTT earns 3000 dollars.
Employee JONES earns 2975 dollars.
Employee ADAMS earns 1100 dollars.
Employee JAMES earns 950 dollars.

6.1.1.3 DBMS_OUTPUT exceptions

DBMS_OUTPUT does not contain any declared exceptions. Instead, Oracle designed the package to rely on two error numbers in the -20 NNN range (usually reserved for Oracle customers). You may, therefore, encounter one of these two exceptions when using the DBMS_OUTPUT package (no names are associated with these exceptions).

The -20000 error number indicates that these package-specific exceptions were raised by a call to RAISE_APPLICATION_ERROR, which is in the DBMS_STANDARD package.

-20000

ORU-10027: buffer overflow, limit of bytes.

If you receive the -10027 error, you should see if you can increase the size of your buffer with another call to DBMS_OUTPUT.ENABLE.

-20000

ORU-10028: line length overflow, limit of 255 bytes per line.

If you receive the -10028 error, you should restrict the amount of data you are passing to the buffer in a single call to PUT_LINE, or in a batch of calls to PUT followed by NEW_LINE.

You may also receive the ORA-06502 error:

ORA-06502

Numeric or value error.

If you receive the -06502 error, you have tried to pass more than 255 bytes of data to DBMS_OUTPUT.PUT_LINE. You must break up the line into more than one string.

6.1.1.4 DBMS_OUTPUT nonprogram elements

The DBMS_OUTPUT package defines a PL/SQL table TYPE as follows:

TYPE chararr IS TABLE OF VARCHAR2(255) INDEX BY BINARY_INTEGER;

The DBMS_OUTPUT.GET_LINES procedure returns its lines in a PL/SQL table of this type.

6.1.1.5 Drawbacks of DBMS_OUTPUT

Before learning all about this package, and rushing to use it, you should be aware of several drawbacks with the implementation of this functionality:

  • The "put" procedures that place information in the buffer are overloaded only for strings, dates, and numbers. You cannot request the display of Booleans or any other types of data. You cannot display combinations of data (a string and a number, for instance), without performing the conversions and concatentations yourself.

  • You will see output from this package only after your program completes its execution. You cannot use DBMS_OUTPUT to examine the results of a program while it is running. And if your program terminates with an unhandled exception, you may not see anything at all!

  • If you try to display strings longer than 255 bytes, DBMS_OUTPUT will raise a VALUE_ERROR exception.

  • DBMS_OUTPUT is not a strong choice as a report generator, because it can handle a maximum of only 1,000,000 bytes of data in a session before it raises an exception.

  • If you use DBMS_OUTPUT in SQL*Plus, you may find that any leading blanks are automatically truncated. Also, attempts to display blank or NULL lines are completely ignored.

There are workarounds for almost every one of these drawbacks. The solution invariably requires the construction of a package that encapsulates and hides DBMS_OUTPUT. This technique is explained in the Section 6.1.6" section.

6.1.2 Enabling and Disabling Output

The ENABLE and DISABLE procedures enable and disable output from the DBMS_OUTPUT.PUT_LINE (and PUT and PUTF) procedure.

6.1.2.1 The DBMS_OUTPUT.ENABLE procedure

The ENABLE procedure enables calls to the other DBMS_OUTPUT modules. If you do not first call ENABLE, then any other calls to the package modules are ignored. The specification for the procedure is,

PROCEDURE DBMS_OUTPUT.ENABLE  (buffer_size IN INTEGER DEFAULT 20000);

where buffer_size is the size of the buffer that will contain the information stored by calls to PUT and PUT_LINE. The buffer size can be as large as 1,000,000 bytes. You can pass larger values to this procedure without raising an error, but doing so will have no effect besides setting the buffer size to its maximum.

You can call ENABLE more than once in a session. The buffer size will be set to the largest size passed in any call to ENABLE. In other words, the buffer size is not necessarily set to the size specified in the last call.

If you want to make sure that the DBMS_OUTPUT package is enabled in a program you are testing, add a statement like this one to the start of the program:

DECLARE
... declarations ...
BEGIN
DBMS_OUTPUT.ENABLE (1000000);
...
END;

6.1.2.2 The DBMS_OUTPUT.DISABLE procedure

The DISABLE procedure disables all calls to the DBMS_OUTPUT package (except for ENABLE). It also purges the buffer of any remaining lines of information. Here's the specification for the procedure:

PROCEDURE DBMS_OUTPUT.DISABLE;

SQL*Plus and SQL*DBA offer a native command, SET SERVEROUTPUT, with which you can disable the package without having to execute the DISABLE procedure directly. You can use the command as follows:

SQL> SET SERVEROUTPUT OFF

This command is equivalent to the following PL/SQL statement:

DBMS_OUTPUT.DISABLE;

After you execute this command, any calls to PUT_LINE and other modules will be ignored, and you will not see any output.

6.1.2.3 Enabling output in SQL*Plus

Most developers use DBMS_OUTPUT almost exclusively in the SQL*Plus environment. To enable output from calls to PUT_LINE in SQL*Plus, you will use the SET SERVEROUTPUT command,

SET SERVEROUTPUT ON SIZE 1000000

or:

SET SERVEROUTPUT ON

Each of these calls the DBMS_OUTPUT.ENABLE procedure.

I have found it useful to add SET SERVEROUTPUT ON SIZE 1000000 to my login.sql file, so that the package is automatically enabled whenever I go into SQL*Plus. (I guess that tells you how often I have to debug my code!)

You should also check the Oracle documentation for SQL*Plus to find out about the latest set of options for the SET SERVEROUTPUT command. As of Oracle8, the documentation shows the following syntax for this SET command:

SET SERVEROUT[PUT] {OFF|ON}
[SIZE n] [FOR[MAT] {WRA[PPED]| WOR[D_WRAPPED]|TRU[NCATED]}]

In other words, you have these options when you enable DBMS_OUTPUT in SQL*Plus:

SET SERVEROUTPUT OFF

Turns off the display of text from DBMS_OUTPUT.

SET SERVEROUTPUT ON

Turns on the display of text from DBMS_OUTPUT with the default 2000-byte buffer. This is a very small size for the buffer; I recommend that you always specify a size when you call this command.

SET SERVEROUTPUT ON SIZE NNNN

Turns on the display of text from DBMS_OUTPUT with the specified buffer size (maximum of 1,000,000 bytes).

SET SERVEROUTPUT ON FORMAT WRAPPED

(Available in Oracle 7.3 and later only.) Specifies that you want the text displayed by DBMS_OUTPUT wrapped at the SQL*Plus line length. The wrapping occurs regardless of word separation. This will also stop SQL*Plus from stripping leading blanks from your text. You can also specify a SIZE value with this variation.

SET SERVEROUTPUT ON FORMAT WORD_WRAPPED

(Available in Oracle 7.3 and later only.) Specifies that you want the text displayed by DBMS_OUTPUT wrapped at the SQL*Plus line length. This version respects integrity of "words." As a result, lines will be broken in a way that keeps separate tokens intact. This will also stop SQL*Plus from stripping leading blanks from your text. You can also specify a SIZE value with this variation.

SET SERVEROUTPUT ON FORMAT TRUNCATED

(Available in Oracle 7.3 and later only.) Specifies that you want the text displayed by DBMS_OUTPUT to be truncated at the SQL*Plus line length; the rest of the text will not be displayed. This will also stop SQL*Plus from stripping leading blanks from your text. You can also specify a SIZE value with this variation.

6.1.3 Writing to the DBMS_OUTPUT Buffer

You can write information to the buffer with calls to the PUT, NEW_LINE, and PUT_LINE procedures.

6.1.3.1 The DBMS_OUTPUT.PUT procedure

The PUT procedure puts information into the buffer, but does not append a newline marker into the buffer. Use PUT if you want to place information in the buffer (usually with more than one call to PUT), but not also automatically issue a newline marker. The specification for PUT is overloaded, so that you can pass data in its native format to the package without having to perform conversions,

PROCEDURE DBMS_OUTPUT.PUT (A VARCHAR2);
PROCEDURE DBMS_OUTPUT.PUT (A NUMBER);
PROCEDURE DBMS_OUTPUT.PUT (A DATE);

where A is the data being passed.

6.1.3.1.1 Example

In the following example, three simultaneous calls to PUT place the employee name, department ID number, and hire date into a single line in the DBMS_OUTPUT buffer:

DBMS_OUTPUT.PUT (:employee.lname || ', ' || :employee.fname);
DBMS_OUTPUT.PUT (:employee.department_id);
DBMS_OUTPUT.PUT (:employee.hiredate);

If you follow these PUT calls with a NEW_LINE call, that information can then be retrieved with a single call to GET_LINE.

6.1.3.2 The DBMS_OUTPUT.PUT_LINE procedure

The PUT_LINE procedure puts information into the buffer and then appends a newline marker into the buffer. The specification for PUT_LINE is overloaded, so that you can pass data in its native format to the package without having to perform conversions:

PROCEDURE DBMS_OUTPUT.PUT_LINE (A VARCHAR2);
PROCEDURE DBMS_OUTPUT.PUT_LINE (A NUMBER);
PROCEDURE DBMS_OUTPUT.PUT_LINE (A DATE);

The PUT_LINE procedure is the one most commonly used in SQL*Plus to debug PL/SQL programs. When you use PUT_LINE in these situations, you do not need to call GET_LINE to extract the information from the buffer. Instead, SQL*Plus will automatically dump out the DBMS_OUTPUT buffer when your PL/SQL block finishes executing. (You will not see any output until the program ends.)

Of course, you can also call DBMS_OUTPUT programs directly from the SQL*Plus command prompt, and not from inside a PL/SQL block, as shown in the following example.

6.1.3.2.1 Example

Suppose that you execute the following three statements in SQL*Plus:

SQL> exec DBMS_OUTPUT.PUT ('I am');
SQL> exec DBMS_OUTPUT.PUT (' writing ');
SQL> exec DBMS_OUTPUT.PUT ('a ');

You will not see anything, because PUT will place the information in the buffer, but will not append the newline marker. When you issue this next PUT_LINE command,

SQL> exec DBMS_OUTPUT.PUT_LINE ('book!');

you will then see the following output:

I am writing a book!

All of the information added to the buffer with the calls to PUT waited patiently to be flushed out with the call to PUT_LINE. This is the behavior you will see when you execute individual calls at the SQL*Plus command prompt to the put programs.

If you place these same commands in a PL/SQL block,

BEGIN
DBMS_OUTPUT.PUT ('I am');
DBMS_OUTPUT.PUT (' writing ');
DBMS_OUTPUT.PUT ('a ');
DBMS_OUTPUT.PUT_LINE ('book');
END;
/

the output from this script will be exactly the same as that generated by this single call:

SQL> exec DBMS_OUTPUT.PUT_LINE ('I am writing a book!');

6.1.3.3 The DBMS_OUTPUT.NEW_LINE procedure

The NEW_LINE procedure inserts an end-of-line marker in the buffer. Use NEW_LINE after one or more calls to PUT in order to terminate those entries in the buffer with a newline marker. Here's the specification for NEW_LINE:

PROCEDURE DBMS_OUTPUT.NEW_LINE;

6.1.4 Retrieving Data from the DBMS_OUTPUT Buffer

You can use the GET_LINE and GET_LINES procedures to extract information from the DBMS_OUTPUT buffer. If you are using DBMS_OUTPUT from within SQL*Plus, however, you will never need to call either of these procedures. Instead, SQL*Plus will automatically extract the information and display it on the screen for you.

6.1.4.1 The DBMS_OUTPUT.GET_LINE procedure

The GET_LINE procedure retrieves one line of information from the buffer. Here's the specification for the procedure:

PROCEDURE DBMS_OUTPUT.GET_LINE
(line OUT VARCHAR2,
status OUT INTEGER);

The parameters are summarized in the following table.

Parameter

Description

line

Retrieved line of text

status

GET request status

The line can have up to 255 bytes in it, which is not very long. If GET_LINE completes successfully, then status is set to 0. Otherwise, GET_LINE returns a status of 1.

Notice that even though the PUT and PUT_LINE procedures allow you to place information into the buffer in their native representations (dates as dates, numbers and numbers, and so forth), GET_LINE always retrieves the information into a character string. The information returned by GET_LINE is everything in the buffer up to the next newline character. This information might be the data from a single PUT_LINE or from multiple calls to PUT.

6.1.4.1.1 Example

The following call to GET_LINE extracts the next line of information into a local PL/SQL variable:

FUNCTION get_next_line RETURN VARCHAR2
IS
return_value VARCHAR2(255);
get_status INTEGER;
BEGIN
DBMS_OUTPUT.GET_LINE (return_value, get_status);
IF get_status = 0
THEN
RETURN return_value;
ELSE
RETURN NULL;
END IF;
END;

6.1.4.2 The DBMS_OUTPUT.GET_LINES procedure

The GET_LINES procedure retrieves multiple lines from the buffer with one call. It reads the buffer into a PL/SQL string table. Here's the specification for the procedure:

PROCEDURE DBMS_OUTPUT.GET_LINES
(lines OUT DBMS_OUTPUT.CHARARR,
numlines IN OUT INTEGER);

The parameters for this procedure are summarized in the following table.

Parameter

Description

lines

PL/SQL array where retrieved lines are placed

numlines

Number of individual lines retrieved from the buffer and placed into the array

The lines parameter is a PL/SQL table TYPE declared in the specification of the package. It is described at the beginning of this chapter.

The values retrieved by GET_LINES are placed in the first numlines rows in the table, starting from row one. As indicated in the PL/SQL table structure, each line (row in the table) may contain up to 255 bytes.

Notice that numlines is an IN OUT parameter. The IN aspect of the parameter specifies the number of lines to retrieve. Once GET_LINES is done retrieving data, however, it sets numlines to the number of lines actually placed in the table. If you ask for ten rows and there are only six in the buffer, then you need to know that only the first six rows of the table are defined.

Notice also that even though the PUT and PUT_LINE procedures allow you to place information into the buffer in their native representations (dates as dates, numbers and numbers, and so forth), GET_LINES always retrieves the information into a character string. The information in each line returned by GET_LINES is everything in the buffer up to the next newline character. This information might be the data from a single PUT_LINE or from multiple calls to PUT.

While GET_LINES is provided with the DBMS_OUTPUT package, it is not needed to retrieve information from the DBMS_OUTPUT buffer -- at least when used inside SQL*Plus. In this interactive query tool, you simply execute calls to PUT_LINE, and when the PL/SQL block terminates, SQL*Plus will automatically dump the buffer to the screen.

6.1.4.2.1 Example

The following script demonstrates both the kind of code you would write when using the GET_LINES procedure, and also the way in which the PL/SQL table is filled:

/* Filename on companion disk: getlines.tst */*
DECLARE
output_table DBMS_OUTPUT.CHARARR; /* output_buf_tab */
a_line VARCHAR2(10) := RPAD('*',10,'*');
status INTEGER;
max_lines CONSTANT NUMBER := 15;
BEGIN
output_table (0) := 'ABC';
output_table (12) := 'DEF';

/* Output 10 lines */
FOR linenum IN 1..10
LOOP
DBMS_OUTPUT.PUT_LINE (a_line || TO_CHAR (linenum);
END LOOP;
/* retrieve 15 lines, status will receive the line count */
status := max_lines;
DBMS_OUTPUT.GET_LINES ( output_table, status);
DBMS_OUTPUT.PUT_LINE ('lines retrieved= ' || status));

FOR linenum in 0..max_lines
LOOP
BEGIN
DBMS_OUTPUT.PUT_LINE
(linenum || ':' || NVL (output_table(linenum),'') );
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE (linenum || ':' || sqlerrm );
END;
END LOOP;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE ('Exception, status=' || status);
DBMS_OUTPUT.PUT_LINE (SQLERRM );
END;
/

Here is the output from the execution of this script:

lines retrieved= 10
0:ORA-01403: no data found
1:**********1
2:**********2
3:**********3
4:**********4
5:**********5
6:**********6
7:**********7
8:**********8
9:**********9
10:**********10
11:
12:ORA-01403: no data found
13:ORA-01403: no data found
14:ORA-01403: no data found
15:ORA-01403: no data found

You can therefore deduce the following rules:

  1. The PL/SQL table is filled starting with row 1.

  2. If DBMS_OUTPUT.GET_LINES finds N lines of data to pass to the PL/SQL table, it sets row N+1 in that table to NULL.

  3. All other rows in the PL/SQL table are set to "undefined." In other words, any other rows that might have been defined before the call to GET_LINES are deleted.

6.1.5 Tips on Using DBMS_OUTPUT

As noted at the beginning of the chapter, DBMS_OUTPUT comes with several handicaps. The best way to overcome these handicaps is to create your own layer of code over the built-in package. This technique is explored in the Section 6.1.6" section.

Regardless of the use of an encapsulation package, you should keep the following complications in mind as you work with DBMS_OUTPUT:

  1. If your program raises an unhandled exception, you may not see any executed output from PUT_LINE, even if you enabled the package for output.

    This can happen because the DBMS_OUTPUT buffer will not be flushed until it is full or until the current PL/SQL block completes its execution. If a raised exception never gets handled, the buffer will not be flushed. As a result, calls to the DBMS_OUTPUT.PUT_LINE module might never show their data. So if you are working with DBMS_OUTPUT.PUT_LINE and are frustrated because you are not seeing the output you would expect, make sure that you have:

    1. Enabled output from the package by calling SET SERVEROUTPUT ON in SQL*Plus.

    2. Placed an exception section with a WHEN OTHERS handler in the outer block of your code (usually some sort of test script) so that your output can be flushed to your terminal by SQL*Plus.

  2. When package state has been reinitialized in your session, DBMS_OUTPUT is reset to "not enabled."

    Packages can be reset to their initial state with a call to DBMS_SESSION.RESET_PACKAGE. (See Chapter 11, Managing Session Information, for more information about this program.) You might call this procedure yourself, but that is unlikely. A more common scenario for resetting package states is when an error is raised in your session that causes packages to be reset to their initial state. Here is the error for which you need to beware:

     ERROR at line 1:/*
    ORA-04068: existing state of packages has been discarded
    ORA-04061: existing state of package "PKG.PROC" has been invalidated
    ORA-04065: not executed, altered or dropped package "PKG.PROC"
    ORA-06508: PL/SQL: could not find program unit being called

If you get this error and simply continue with your testing, you may be surprised to find that you are not getting any output. If you remember that DBMS_OUTPUT relies on package variables for its settings, this makes perfect sense. So when you get the preceding error, you should immediately "re-enable" DBMS_OUTPUT with a command such as the following:

SQL> set serveroutput on size 1000000 format wrapped

I usually just re-execute my login.sql script, since I may be initializing several different packages:

SQL> @login.sql

When will you get this error? I have found that it occurs when I have multiple sessions connected to Oracle. Suppose that I am testing program A in session USER1. I run it and find a bug. I fix the bug and recompile program A in session USER2 (the owner of the code). When I try to execute program A from session USER1 again, it raises the ORA-04068 error.

If you do encounter this error, don't panic. Just reset your package variables and run the program again. It will now work fine; the error is simply the result of a quirk in Oracle's automatic recompilation feature.

6.1.6 DBMS_OUTPUT Examples

This section contains several longer examples of DBMS_OUTPUT operations.

6.1.6.1 Encapsulating DBMS_OUTPUT

Sure, it was nice of Oracle Corporation to give us the DBMS_OUTPUT package. Without it, as users of PL/SQL 1.0 found, we are running blind when we execute our code. As is the case with many of the developer-oriented utilities from Oracle, however, the DBMS_OUTPUT package is not a polished and well-planned tool. It offers nothing more than the most basic functionality, and even then it is crippled in some important ways. When I started to use it in real life (or whatever you might call the rarified atmosphere of authoring a book on software development), I found DBMS_OUTPUT.PUT_LINE to be cumbersome and limiting in ways.

I hated having to type "DBMS_OUTPUT.PUT_LINE" whenever I simply wanted to display some information. That's a mouthful and a keyboardful. I felt insulted that they hadn't even taken the time to overload for Booleans, requiring me to write silly IF logic just to see the value of a Boolean variable or function. I also found myself growing incensed that DBMS_OUTPUT would actually raise a VALUE_ERROR exception if I tried to pass it a string with more than 255 characters. I had enough errors in my code without having to worry about DBMS_OUTPUT adding to my troubles.

I decided that all this anger and frustration was not good for me. I needed to move past this nonconstructive lashing out at Oracle. I needed, in short, to fix my problem. So I did -- with a package of my own. I am not going to provide a comprehensive explanation of my replacement package, but you can read about it (there are actually two of them) in my other books as follows:

Oracle PL/SQL Programming

The Companion Disk section on "Package Examples" introduces you to the do package, which contains the do.pl procedure, a substitute for DBMS_OUTPUT.PUT_LINE. The do.sps and do.spb files in the book you are reading also contain the source code for this package.

Advanced Oracle PL/SQL Programming with Packages

Chapter 7, p: A Powerful Substitute for DMBS_OUTPUT, presents the p package and the p.l procedure (I told you I didn't like typing those long program names!), a component of the PL/Vision library.[2]

[2] A version of PL/Vision is available through a free download from the http://www.revealnet.com site.

The following section shows you the basic elements involved in constructing an encapsulation around DBMS_OUTPUT.PUT_LINE, which compensates for many of its problems. You can pursue building one of these for yourself, but I would strongly suggest that you check out the PL/Vision p package. That will leave you more time to build your own application-specific code.

6.1.6.2 Package specification for a DBMS_OUTPUT encapsulator

The absolute minimum you need for such an encapsulator package is an overloading of the "print" procedure for dates, strings, and numbers. Let's at least add Booleans to the mix in this prototype:

/* Filename on companion disk: prt.spp */*
CREATE OR REPLACE PACKAGE prt
IS
c_prefix CONSTANT CHAR(1) := '*';
c_linelen CONSTANT INTEGER := 80;

PROCEDURE ln (val IN VARCHAR2);
PROCEDURE ln (val IN DATE);
PROCEDURE ln (val IN NUMBER);
PROCEDURE ln (val IN BOOLEAN);
END;
/

The prefix constant is concatenated to the beginning of any string to be displayed to avoid the problem of truncated spaces and ignored lines in SQL*Plus. The line length constant is used when the string is longer than 255 bytes. Finally, each of the prt.ln procedures prints a different type of data.

A complete implementation of this package would allow you to change the line length and the prefix, specify a date format for conversion, and so on. Again, check out the p package of PL/Vision for such a package.

Here is the body of the prt package:

/* Filename on companion disk: prt.spp */*
CREATE OR REPLACE PACKAGE BODY prt
IS
PROCEDURE ln (val IN VARCHAR2)
IS
BEGIN
IF LENGTH (val) > 255
THEN
PLVprs.display_wrap (val, c_linelen);
ELSE
DBMS_OUTPUT.PUT_LINE (c_prefix || val);
END IF;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.ENABLE (1000000);
DBMS_OUTPUT.PUT_LINE (c_prefix || val);
END;
PROCEDURE ln (val IN DATE)
IS
BEGIN
ln (TO_CHAR (val));
END;
PROCEDURE ln (val IN NUMBER)
IS
BEGIN
ln (TO_CHAR (val));
END;
PROCEDURE ln (val IN BOOLEAN)
IS
BEGIN
IF val
THEN
ln ('TRUE');
ELSIF NOT val
THEN
ln ('FALSE');
ELSE
ln ('NULL BOOLEAN');
END IF;
END;
END;
/

Here are a few things to notice about the package implementation:

  • The string version of prt.ln is the "core" print procedure. The other three programs all call that one, after they have formatted the string appropriately.

  • The Boolean version of prt.ln simply performs the same IF logic you would have to write if you were using DBMS_OUTPUT. By hiding it inside the prt procedure, though, nobody else has to write that kind of code again. Plus, it handles NULL values.

  • The string version of prt.ln contains all the complex logic. For long strings, it relies on the PL/Vision display wrap procedure of the PLVprs package.[3] For strings with fewer than 256 characters, it calls DBMS_OUTPUT.PUT_LINE.

    [3] Available through a free download from the http://www.revealnet.com site.

  • As an added feature, if the attempt to display using DBMS_OUTPUT.PUT_LINE raises an exception, prt.ln assumes that the problem might be that the buffer is too small. So it increases the buffer to the maximum possible value and then tries again. I believe that it is very important for developers to make the extra effort to increase the usefulness of our code.

The prt package should give you a solid idea about the way to encapsulate a built-in package inside a package of your own construction.

SANworks Data Replication Manager (DRM)

SANworks Data Replication Manager (DRM) เป็นโซลูชั่นที่มีเอกลักษณ์เฉพาะตัว ได้รับการออกแบบมาเพื่อเก็บข้อมูลด้วยวิธี mirroring data online และทำงานแบบ real time จากพื้นที่รีโมทไกลผ่านมายังพื้นที่โลคัล หรือเครือข่าย Storage Area Network (SAN) ด้วยซอฟท์แวร์นี้การรีพลิเคทข้อมูลจะทำงานที่ระบบเก็บข้อมูลและที่แบ็คกราวน์ของโฮสท์ต่างๆ

SANworks Data Replication Manager (DRM)

จุดเด่นผลิตภัณฑ์

  • ทำการรีพลิเคทข้อมูลทั้งแบบออนไลน์และแบบเรียลไทม์ไปยังพื้นที่โลคัล หรือพื้นที่ห่างไกล
  • ทำการรีพลิเคทข้อมูลผ่านช่องไฟเบอร์บนเครือข่าย SAN หรือ เครือข่าย SAN/MAN/WAN/MAN/SANสนับสนุนการทำงานร่วมกับระบบปฏิบัติการหลายระบบเช่น Microsoft Win 2000/NT, Compaq Tru64, Compaq Open VMS, Sun Solaris, Novel Netware and IBM AIX รวมถึงโฮสท์เซิร์ฟเวอร์ในการใช้งานบนเครือข่าย LAN/SAN
  • สนับสนุนการทำงานร่วมกับระบบ MA8000/EMA12000/EMA16000 อัพเกรดมาจาก RA8000/ESA12000 ซึ่งเป็นโซลูชั่นสำหรับเก็บข้อมูลผ่านช่องไฟเบอร์ที่สนับสนุนไดร๊ฟหลากหลายชนิด
  • สนับสนุน FC Switch Zoning และ Cascaded switches
  • มีโหมดในการส่งข้อมูลทั้งแบบส่งพร้อมกัน และส่งไม่พร้อมกัน
  • ทำการรีพลิเคทได้ไกลถึง 100 กิโลเมตร (62 ไมล์) ด้วยความเร็วในการส่ง 100เมกะบิตต่อวินาที
  • ใช้โซลูชั่นแบบ Active/Active Bi-directional
  • ทำงานร่วมกับ SANworks Command Scripter V1.0A, SANworks Secure Path, SANworks Virtual Replicator V2.0, SANworks Enterprise Volume Manager รวมทั้งสนับสนุน SAP
  • ช่วยในการ failover และ failback ทำให้คุณมั่นใจว่าข้อมูลจะอยู่ครบ พร้อมใช้งานได้เสมอ
  • มีความสามารถในการ clone ได้ทั้งพื้นที่เริ่มต้นและพื้นที่เป้าหมาย และมีความสามารถในการทำ Snapshot ที่พื้นที่เป้าหมาย ซึ่งการ Clone และการ Snapshot เป็นฟังก์ชั่นในการก็อปปี้ข้อมูลที่ช่วยลดการเกิด downtime สำหรับระบบการสำรองข้อมูลและการเคลื่อนย้ายข้อมูล

SANworks Enterprise Volume Manager (EVM) เป็นโซลูชั่นการจัดการบนเครือข่าย SAN โดยทำหน้าที่เป็นตัวควบคุมการปฏิบัติการ clone และ snapshot ซึ่งการ Clone และการ snapshot เป็นการก๊อปปี้ volumes ซึ่งสามารถนำไปใช้กำจัดการเกิด downtime สำหรับระบบการสำรองข้อมูล เช่นเดียวกับช่วยแบ่งเบาภาระงานอื่นๆ จากศูนย์ข้อมูลได้เป็นอย่างดี EVM โซลูชั่นนี้จะรองรับความต้องการของธุรกิจให้สามารถทำงานอย่างต่อเนื่องโดยรันระบบปฏิบัติการการแบ็คอัพด้วย snapshots และ clones เป็นกระบวนการทำ parallel ให้เป็นกระบวนการแอพพลิเคชั่นทั่วไป EVM ได้รับการออกแบบมาสำหรับลูกค้าที่ไม่ต้องการหรือไม่สามารถขัดจังหวะการปฏิบัติงานของคอมพิวเตอร์ด้วยกิจกรรมอย่างการสำรองข้อมูลได้ ด้วยข้อมูลมหาศาล การปฏิบัติการสำรองข้อมูลทั่วไปไม่สามารถทำได้สมบูรณ์ด้วยหน้าต่างการสำรองข้อมูลเพียงหน้าต่างเดียว โดย EVM จะกำจัดความจำเป็นที่จะต้องใช้หน้าต่างสำรองข้อมูล โดยอนุญาตให้สามารถปฏิบัติการแบบ non-disruptive หรือกู้ข้อมูลได้ ทำการสำรองข้อมูลจาก clone หรือ snapshot ในแบ็คกราวน์ได้ตลอดเวลา

SANworks Enterprise Volume Manager (EVM)

จุดเด่นผลิตภัณฑ์

  • เป็นสถาปัตยกรรมใหม่ที่พัฒนามาจากเวอร์ชั่นก่อน เพื่อให้สามารถรันบน Compaq SANworks ได้
  • รองรับความต้องการการใช้งานบนเครือข่าย SAN ขององค์กรต่างๆ ด้วยความสามารถที่จัดการกับระบบการเก็บข้อมูล HSG80 โดยไม่จำกัดจำนวนโฮสท์ของ EVM hosts โดย EVM สามารถรันงานต่างๆ ของ EVM ผ่านระบบการเก็บข้อมูลได้หลายระบบโดยไม่ส่งผลกระทบต่อการทำงานของโฮสท์ของผู้ใช้
  • สนับสนุนการทำงานของโฮสท์ต่างๆ ที่ทำงานด้วยระบบปฏิบัติการที่ต่างกัน
  • ใช้ง่ายและมีความยืดหยุ่นในการใช้งาน สามารถทำงานที่มีความซับซ้อนได้ ตัวอย่างเช่น การสำรองข้อมูลแบบ non-disruptive, การใช้ snapshots และ clones เป็นวิธีง่ายๆ ที่ EVM เวอร์ชั่น 2.0 มีให้ โดยจะชี้แจงรายละเอียดเกี่ยวกับคอนฟิกเกอเรชั่นของเครือข่าย SAN บนโซลูชั่น EVM บนหน้าจอ
  • สนับสนุนระบบปฏิบัติการหลายระบบ เช่น Windows NT, Windows 2000 operating systemsHP -UX, IBM-AIX, และ Sun Solaris และในช่วงไตรมาศแรกของปี 2002 จะสามารถใช้ได้กับ Tru64 with AdvFS and LSM และ OVMS
  • ลดจำนวน Volume ด้วยการทำ Cloning และ Snapshot
  • สนับสนุนระบบการเก็บข้อมูลที่ใช้เทคนิค RAID Array 8000 (RA8000), Enterprise Storage Array 12000 (ESA12000), Modular Array 8000 (MA 8000), the Enterprise Modular Array 12000 (EMA 12000), and the Enterprise Modular Array 16000 (EMA 16000) ที่ใช้ HSG80 เป็นตัวควบคุมสนับสนุนการทำงานร่วมกับซอฟท์แวร์หลายตัวเช่น Microsoft Exchange, Oracle, Microsoft SQL, VERITAS NetBackup, VERITAS Backup Exec, Legato NetWorker, CA ARCServeIT, และ StorageWorks Enterprise Backup Solution ซึ่งในมีโครงการจะรองรับแอพพลิเคชั่นอื่นๆ ในอนาคต
  • รันการสำรองข้อมูลจาก snapshot หรือ clone อย่างเป็นอิสระโดยไม่รบกวนงานอื่นที่กำลังทำอยู่
  • ใช้งานง่าย และทำให้มั่นใจว่าข้อมูลจะยังอยู่ครบและใช้งานได้

SANworks Secure Path เป็นหนึ่งในตระกูลซอฟท์แวร์ที่มีเสถียรภาพในการ multi-pathing สูง ช่วยให้สามารถรับ-ส่งข้อมูลได้อย่างต่อเนื่องจาก RAID Array ของ Compaq ส่งไปยังโฮสท์เซิร์ฟเวอร์ที่รันบนระบบปฏิบัติการ Windows 2000, Windows NT, Sun Solaris, Novell NetWare, IBM AIX, และ HP -UX เทคโนโลยี RAID บวกกับความสามารถในการ failover ได้ถูกนำมาใช้เพื่อแก้ไขข้อบกพร่อง Secure Path ทำงานอย่างได้ผลโดยจะกำจัดตัวควบคุม, ดิสก์ไดร๊ฟ, การเชื่อมต่อฮาร์ดแวร์ และอะแด็ปเตอร์โฮสท์บัส จากจุดที่เกิดความเสียหายเพียงจุดเดียวในระบบการเก็บข้อมูลย่อย

1. Secure Path V3.0 for HP -UX เป็นซอฟท์แวร์แบบ multi-path ที่มีเสถียรภาพสูง ซึ่งสามารถจัดการและรักษาความต่อเนื่องในการเรียกใช้ข้อมูลจากระบบสตอเรจของ Compaq ได้เป็นอย่างดี โดยปราศจากการทำงานล้มเหลวจากเซิร์ฟเวอร์ไปยังสตอเรจ SANworks Secure Path สำหรับ HP -UX เป็นซอฟท์แวร์ที่ติดตาม path ข้อมูลระหว่างเซิร์ฟเวอร์กับสตอเรจเพื่อเพิ่มเสถียรภาพของข้อมูล ในกรณีที่พบว่า path ใช้งานไม่ได้ SANworks Secure Path สำหรับ HP -UX จะทำการ failover ไปยัง path อีก path หนึ่ง เมื่อใดก็ตามที่ path ดั้งเดิมใช้งานได้แล้ว SANworks Secure Path สำหรับ HP -UX ก็จะกลับไป failback ที่ path เดิม SANworks Secure Path สำหรับ HP -UX ยังสามารถสร้างความสมดุลของงานโหลด โดยแบ่งไปตาม path ต่างๆ เพื่อให้ทำงานได้อย่างมีประสิทธิภาพสูงสุด

Secure Path V3.0 for HP -UX

2. Secure Path V3.0 for Sun Solaris จัดการและดูแลข้อมูลให้กับระบบเก็บข้อมูลของ Compaq เพื่อให้สามารถเข้าใช้งานได้ตลอดเวลา โดยไม่ประสบกับปัญหาใช้งานไม่ได้ตั้งแต่เซิร์ฟเวอร์ไปจนถึงสตอเรจ SANworks Secure Path สำหรับ Sun Solaris เป็นซอฟท์แวร์ที่ติดตามเส้นทางข้อมูลระหว่างเซิร์ฟเวอร์กับสตอเรจ เพื่อเพิ่มเสถียรภาพของข้อมูล ในกรณีที่พบว่า path ใช้งานไม่ได้ SANworks Secure Path สำหรับ Sun Solaris จะทำการ failover ไปยังอีก path หนึ่ง และเมื่อ path เดิมใช้งานได้แล้ว SANworks Secure Path สำหรับ Sun Solaris ก็จะกลับไปทำงานตามเดิมโดยอัตโนมัติที่ path เดิมของตน นอกจากนี้ SANworks Secure Path สำหรับ Sun Solaris ยังสร้างความสมดุลให้กับงานโหลดทั้งหลายโดยแบ่งไปยัง path ต่างๆ เพื่อให้ระบบทำงานได้อย่างมีประสิทธิภาพสูงสุด SANworks Secure Path V3.0 สำหรับ Sun Solaris สนับสนุนโฮสท์ของ ในการเชื่อมต่อกับ Compaq StorageWorks Modular Array 8000 (MA8000) / Enterprise Modular Array 12000 (EMA12000) / Enterprise Modular Array 16000 (EMA16000) และ StorageWorks RAID Array 8000/Enterprise Storage Array 12000 (RA8000/ESA12000) storage solutions

Secure Path V3.0 for Sun Solaris

จุดเด่นผลิตภัณฑ์

  • ทำการ failover และ failback ได้มากถึง 32 path ต่อ 1 LUN ทำให้มั่นใจได้ว่า path ระหว่างแอพพลิเคชั่นกับข้อมูลของคุณจะยังคงอยู่ตลอดเวลา
  • สามารถทำการปรับเปลี่ยน add/remove LUNs, HBA's และ คอนโทรลเลอร์ ได้ ทำให้สามารถทำงานกับ Enterprise Volume Manager ได้อย่างสมบูรณ์ และคงคุณภาพไว้ได้
  • LUNs ได้รับการทำพาร์ทิชั่นบนหลายโฮสท์ ซึ่งโฮสท์ตั้งแต่สองโฮสท์ขึ้นไปสามารถแชร์สตอเรจร่วมกันได้ ให้สามารถใช้เรียกใช้งานจากแหล่งข้อมูลได้ประสิทธิภาพสูงสุด
  • สร้างความสมดุลให้กับงานโหลด เพราะสามารถแบ่งงานไปตาม path ต่างๆ ให้ช่วยกันทำงานอย่างมีประสิทธิภาพ
  • สนับสนุน HBAs ได้มากถึง 16 HBAs ต่อ หนึ่งโฮสท์ เป็นการสนับสนุนระบบที่ใหญ่ขึ้นด้วย HBAs ที่มากขึ้น

Wednesday, March 12, 2008

How to Create a PHP Calendar

How to Create a PHP Calendar
with Don Schechter


PHP calendars can be used for everything from simply displaying the date to creating complex reservation systems. See the steps to starting your own PHP calendar.

Display date and time with PHP

Display date and time with PHP
Example:

$b = time ();
print date("g:i:s A D, F jS Y",$b);

Output: 02:10:10 PM Tue, March 12th 2008

PHP Date/Time Variables

If you're looking to customize your date/time display, here are the variables to use:

Days
d - day of the month 2 digits (01-31)
j - day of the month (1-31)
D - 3 letter day (Mon - Sun)
l - full name of day (Monday - Sunday)
N - 1 = Monday, 2 = Tuesday, etc. (1-7)
S - suffix for date (st, nd, rd)
w - 0 = Sunday, 1 = Monday (0-6)
z - day of the year (1 = 365)


Week
W - week of the year (1-52)


Month
F - Full name of month (January - December)
m - 2 digit month number (01-12)
n - month number (1-12)
M - 3 letter month (Jan - Dec)
t - Days in the month (28-31)


Year
L - leap year (0 no, 1 yes)
o - ISO-8601 year number (e.g. GMT, CST)
I - daylight savings (1 = yes, 0 = no)
O - offset GMT (e.g. 0200)
Z - offset in seconds (-43200 - 43200)
r - full RFC 2822 formatted date

Tuesday, March 11, 2008

Symantec ManHunt™ - Basic command

Symantec ManHunt™ - Basic command

manhunt install path: /usr/manhunt

start -
Start manhunt process
stop -
Stop manhunt process
restart -
Restart manhunt process

manhunt tools: /usr/manhunt/tools
adduser
dumplog.sh
manual-trigger
nodepwd
setuserpassword

backupdbs
edppwd
mhdrv-ctl
promote-demote
sigc

checkstatus
log2html.pl
mh_els_lit
re1000gdump
sym_sid

dbverify.sh
logtotext
mh-handoff-console
rotatelogs

======================================
Example:
[root@Octus]#/usr/manhunt/restart

shutting down ManHunt server
----------------------------
stopping status monitor [11914]
stopping AF... OK.
stopping other processes:
stopping alertd [11834]
stopping avmon [11881]
stopping dbsync [11904]
stopping edprcvr [11864]
stopping esp [11851]
stopping fds [11901]
stopping ftf [11816]
stopping handoff [11823]
stopping memdb [11822]
stopping mhdb.020 [11762]
stopping qspmon [11965]
stopping qspproxy [11856]
stopping resourced [11811]
stopping sniffmon [11838]
waiting for processes to clean up.... OK.
stopping mhlogd [11796]...OK.
done.
please wait...
starting...

starting manhunt....
database up and running.
please wait... done.

displays information about processors in SunOS

psrinfo - displays information about processors

SYNOPSIS
psrinfo [ -p ] [ -v ] [ processor_id ... ]
psrinfo [ -p ] -s processor_id

OPTIONS
The following options are supported:

-s processor_id
Silent mode. Displays 1 if the specified processor is
fully on-line, and 0 if the specified processor is
non-interruptible, off-line, or powered off.

Use silent mode when using psrinfo in shell scripts.

-p Display the number of physical processors in a system.

When combined with the -v option, reports additional
information about each physical processor.

-v Verbose mode. Displays additional information about
the specified processors, including: processor type,
floating point unit type and clock speed. If any of
this information cannot be determined, psrinfo
displays unknown.

When combined with the -p option, reports additional
information about each physical processor.

HOW TO USE?
==========================
Normal command
root@octus # psrinfo
130 on-line since 07/28/04 02:05:18
131 on-line since 07/28/04 02:05:18
132 on-line since 07/28/04 02:05:18
=============================
Command with option
root@octus # psrinfo -v
Status of processor 130 as of: 03/11/04 17:00:22
Processor has been on-line since 07/28/04 02:05:18.
The sparcv9 processor operates at 2050 MHz,
and has a sparcv9 floating point processor.

.........
....
..
===================================
CPU Number
root@octus # psrinfo |wc -l
3