You are on page 1of 19

USER_EXIT: A WAY IN WHICH TO PASS CONTROL (AND POSSIBLY ARGUMENTS) FROM DEVELOPER/2000 TO ANOTHER ORACLE PRODUCT OR 3GL, AND

THEN RETURN CONTROL (AND POSSIBLY ARGUMENTS) BACK TO DEVELOPER/2000.

FOREIGN FUNCTIONS ARE SUBPROGRAMS WRITTEN IN A 3GL PROGRAMMING LANGUAGE THAT ALLOW YOU TO CUSTOMIZE YOUR FORM BUILDER APPLICATIONS TO MEET THE UNIQUE REQUIREMENTS OF YOUR USERS. FOREIGN FUNCTIONS ARE OFTEN USED TO ENHANCE PERFORMANCE OR PROVIDE ADDITIONAL FUNCTIONALITY TO FORM BUILDER. IN FORM BUILDER, YOU CAN CALL A USER EXIT FROM WITHIN A TRIGGER OR USER-NAMED SUBPROGRAM USING THE USER_EXIT BUILT-IN. THE USER EXIT MUST BE WRITTEN TO RETURN AN INTEGER VALUE STATUS CODE FROM THE FUNCTION. THE RETURN VALUE OF THE USER EXIT INDICATES SUCCESS, FAILURE, OR FATAL ERROR. FOLLOWING THE EXECUTION OF THE USER_EXIT BUILT-IN, THE VALUES OF THE ERROR VARIABLES IN FORM BUILDERFORM_FAILURE, FORM_FATAL, AND FORM_SUCCESSARE SET ACCORDINGLY. SPECIAL HANDLING IS REQUIRED TO MAKE A USER EXIT CALLABLE FROM FORMS RUNTIME. WHEN USING A USER EXITS ON MICROSOFT WINDOWS, YOUR USER EXIT FUNCTIONS MUST BE LINKED INTO A DYNAMIC LINK LIBRARY, AND A SPECIAL CONFIGURATION LIBRARY MUST BE UPDATED WITH INFORMATION ABOUT EACH USER EXIT. THE CONFIGURATION FILE PROVIDES INFORMATION ABOUT THE USER EXIT INTERFACES AND THE ENTRY POINTS THAT ALLOW FORM BUILDER TO INVOKE FOREIGN FUNCTIONS FROM A USER EXIT INTERFACE. WHEN USING USER EXITS ON OTHER PLATFORMS, A CONFIGURATION FILE MUST BE UPDATED WITH INFORMATION ABOUT EACH USER EXIT, AND THE COMPILER VERSION OF THAT FILE, PLUS THE COMPILED VERSION OF THE USER EXIT CODE, MUST BE LINKED INTO THE FORMS RUNTIME EXECUTABLE. YOU CAN PASS PARAMETERS TO A FOREIGN FUNCTION THAT IS INVOKED FROM A USER EXIT. YOU CAN PASS PARAMETER VALUES BY DEFINING USER_EXIT_STRING AND ERROR_STRING IN THE USER_EXIT BUILT-IN SUBPROGRAM. WHEN YOU DEFINE USER_EXIT_STRING AND ERROR_STRING IN FORM BUILDER, THE FOREIGN FUNCTION RECOGNIZES THE VALUES AS CORRESPONDING TO A COMMAND LINE VALUE AND AN ERROR MESSAGE VALUE. FOR INSTANCE, FORM BUILDER TREATS THE VALUE OF USER_EXIT_STRING AS A STRING VARIABLE. THE VALUE OF USER_EXIT_STRING IS THE COMMAND LINE TO A FOREIGN FUNCTION. THE FOLLOWING ARE FOREIGN FUNCTION PARAMETERS AND THEIR CORRESPONDING FORM BUILDER DEFINITIONS FOR EACH FOREIGN FUNCTION INVOKED FROM A USER EXIT: FOREIGN FUNCTION PARAMETER FORM BUILDER DEFINITION COMMAND LINE USER_EXIT_STRING. COMMAND LINE LENGTH LENGTH (IN CHARACTERS) OF USER_EXIT_STRING. ERROR MESSAGE ERROR_STRING. ERROR MESSAGE LENGTH LENGTH (IN CHARACTERS) OF ERROR_STRING. IN-QUERY A BOOLEAN VALUE THAT REFLECTS WHETHER THE FOREIGN FUNCTION WAS INVOKED FROM A USER EXIT WHEN THE FORM WAS IN ENTER QUERY MODE. ALTHOUGH FORM BUILDER AUTOMATICALLY INVOKES THE FOREIGN FUNCTION FROM THE USER_EXIT_STRING, FORM BUILDER DOES NOT AUTOMATICALLY PARSE THE USER_EXIT_STRING. IT IS THE RESPONSIBILITY OF THE FOREIGN FUNCTION TO PARSE THE USER_EXIT_STRING. YOU CAN PASS ANY NUMBER OF PARAMETERS TO A FOREIGN FUNCTION FROM THE USER_EXIT_STRING OF THE USER_EXIT BUILT-IN. USE THIS FEATURE TO PASS INFORMATION SUCH AS ITEM NAMES. FOR EXAMPLE, TO PASS TWO PARAMETERS, PARAM1 AND PARAM2, TO THE CALCULATE_VALUES FOREIGN FUNCTION, YOU SPECIFY THE FOLLOWING STATEMENT: USER_EXIT('CALCULATE_VALUES PARAM1 PARAM2'); USER_EXIT EXAMPLES /* ** BUILT-IN: USER_EXIT ** EXAMPLE: INVOKE A 3GL PROGRAM BY NAME WHICH HAS BEEN

** PROPERLY LINKED INTO YOUR CURRENT FORM BUILDER ** EXECUTABLE. THE USER EXIT SUBPROGRAM MUST PARSE ** THE STRING ARGUMENT IT IS PASSED TO DECIDE WHAT ** FUNCTIONALITY TO PERFORM. */ PROCEDURE COMMAND_ROBOTIC_ARM( CMD_STRING VARCHAR2 ) IS BEGIN /* ** CALL A C FUNCTION 'ROBOTLNK' TO INITIALIZE THE ** COMMUNICATION CARD BEFORE SENDING THE ROBOT A MESSAGE. */ USER_EXIT('ROBOTLNK INITIALIZE UNIT=6,CMDTOFOLLOW=1'); IF NOT FORM_SUCCESS THEN MESSAGE('FAILED TO INITIALIZE ROBOT 6'); RAISE FORM_TRIGGER_FAILURE; END IF; /* ** PASS THE STRING ARGUMENT AS A COMMAND TO THE ROBOT */ USER_EXIT('ROBOTLNK SEND UNIT=6,MSG='||CMD_STRING ); IF NOT FORM_SUCCESS THEN MESSAGE('COMMAND NOT UNDERSTOOD BY ROBOT 6'); RAISE FORM_TRIGGER_FAILURE; END IF; /* ** CLOSE THE ROBOT'S COMMUNICATION CHANNEL */ USER_EXIT('ROBOTLNK DEACTIVATE UNIT=6'); IF NOT FORM_SUCCESS THEN MESSAGE('FAILED TO DEACTIVATE ROBOT'); RAISE FORM_TRIGGER_FAILURE; END IF; /* ** THE USER EXIT WILL DEPOSIT A TIMING CODE INTO THE ITEM ** CALLED 'CONTROL.ROBOT_STATUS'. */ MESSAGE('COMMAND SUCCESSFULLY COMPLETED BY ROBOT 6'|| ' IN '||TO_CHAR(:CONTROL.ROBOT_TIMING)|| ' SECONDS.'); END; OBJECT GROUP: AN OBJECT GROUP IS A CONTAINER FOR A GROUP OF OBJECTS. YOU DEFINE AN OBJECT GROUP WHEN YOU WANT TO PACKAGE RELATED OBJECTS SO YOU CAN COPY OR SUBCLASS THEM IN ANOTHER MODULE. OBJECT GROUPS PROVIDE A WAY TO BUNDLE OBJECTS INTO HIGHER-LEVEL BUILDING BLOCKS THAT CAN BE USED IN OTHER PARTS OF AN APPLICATION AND IN SUBSEQUENT DEVELOPMENT PROJECTS. FOR EXAMPLE, YOU MIGHT BUILD AN APPOINTMENT SCHEDULER IN A FORM AND THEN DECIDE TO MAKE IT AVAILABLE FROM OTHER FORMS IN YOUR APPLICATIONS. THE SCHEDULER WOULD PROBABLY BE BUILT FROM SEVERAL TYPES OF OBJECTS, INCLUDING A WINDOW AND CANVAS, BLOCKS, AND ITEMS THAT DISPLAY DATES AND APPOINTMENTS, AND TRIGGERS THAT CONTAIN THE LOGIC FOR SCHEDULING AND OTHER FUNCTIONALITY. IF YOU PACKAGED THESE OBJECTS INTO AN OBJECT GROUP, YOU COULD THEN COPY THEM TO ANY NUMBER OF OTHER FORMS IN ONE SIMPLE OPERATION. YOU CAN CREATE OBJECT GROUPS IN FORM AND MENU MODULES. ONCE YOU CREATE AN OBJECT GROUP, YOU CAN ADD AND REMOVE OBJECTS TO IT AS DESIRED.

COPY AN OBJECT WHEN YOU WANT TO CREATE A NEW AND SEPARATE INSTANCE OF THE THE OBJECT. SUBCLASS AN OBJECT WHEN YOU WANT TO CREATE A NEW OBJECT THAT MAINTAINS A LINK TO THE SOURCE OBJECT. ONCE YOU CREATE A SUBCLASSED OBJECT, ANY CHANGES YOU MAKE TO THE SOURCE OBJECT ARE INHERITED BY THE SUBCLASSED OBJECT WHEN YOU OPEN OR RECOMPILE THE MODULE THAT CONTAINS THE SUBCLASSED OBJECT. IF THE BOTH MODULES ARE OPEN, CHANGES ARE INHERITED IMMEDIATELY.
RECORD GROUP:

A RECORD GROUP IS AN INTERNAL FORM BUILDER DATA STRUCTURE THAT HAS A COLUMN/ROW FRAMEWORK SIMILAR TO A DATABASE TABLE. HOWEVER, UNLIKE DATABASE TABLES, RECORD GROUPS ARE SEPARATE OBJECTS THAT BELONG TO THE FORM MODULE IN WHICH THEY ARE DEFINED. A RECORD GROUP CAN HAVE AN UNLIMITED NUMBER OF COLUMNS OF TYPE CHAR, LONG, NUMBER, OR DATE PROVIDED THAT THE TOTAL NUMBER OF COLUMNS DOES NOT EXCEED 64K. RECORD GROUP COLUMN NAMES CANNOT EXCEED 30 CHARACTERS. PROGRAMMATICALLY, RECORD GROUPS CAN BE USED WHENEVER THE FUNCTIONALITY OFFERED BY A TWODIMENSIONAL ARRAY OF MULTIPLE DATA TYPES IS DESIRABLE. A RECORD GROUP BUILT FROM A QUERY CAN STORE RECORDS FROM DATABASE TABLES MUCH LIKE A DATABASE VIEW, WITH THE ADDED ADVANTAGE THAT THE RECORD GROUP IS LOCAL TO FORM BUILDER, RATHER THAN EXISTING IN THE DATABASE. ALSO, THE SELECT STATEMENT USED TO CREATE AND POPULATE A QUERY RECORD GROUP CAN BE CONSTRUCTED DYNAMICALLY AT RUNTIME. THERE ARE THREE TYPES OF RECORD GROUPS: QUERY RECORD GROUPS, STATIC RECORD GROUPS, AND NON-QUERY RECORD GROUPS. QUERY RECORD GROUP A QUERY RECORD GROUP IS A RECORD GROUP THAT HAS AN ASSOCIATED SELECT STATEMENT. THE COLUMNS IN A QUERY RECORD GROUP DERIVE THEIR DEFAULT NAMES, DATA TYPES, AND LENGTHS FROM THE DATABASE COLUMNS REFERENCED IN THE SELECT STATEMENT. THE RECORDS IN A QUERY RECORD GROUP ARE THE ROWS RETRIEVED BY THE QUERY ASSOCIATED WITH THAT RECORD GROUP. NON-QUERY RECORD GROUP A NON-QUERY RECORD GROUP IS A GROUP THAT DOES NOT HAVE AN ASSOCIATED QUERY, BUT WHOSE STRUCTURE AND VALUES CAN BE MODIFIED PROGRAMMATICALLY AT RUNTIME. STATIC RECORD GROUP A STATIC RECORD GROUP IS NOT ASSOCIATED WITH A QUERY; RATHER, YOU DEFINE ITS STRUCTURE AND ROW VALUES AT DESIGN TIME, AND THEY REMAIN FIXED AT RUNTIME. AT DESIGN TIME, YOU CAN CREATE QUERY RECORD GROUPS AND STATIC RECORD GROUPS. AT RUNTIME, YOU CAN PROGRAMMATICALLY CREATE QUERY RECORD GROUPS AND NON-QUERY RECORD GROUPS. WHEN YOU CREATE A RECORD GROUP, YOU DO NOT SPECIFY ITS TYPE EXPLICITLY; RATHER, THE TYPE IS IMPLIED BY WHEN YOU CREATE THE RECORD GROUP (AT DESIGN TIME OR PROGRAMMATICALLY AT RUNTIME) AND BY HOW YOU DEFINE THE GROUP.
EXECEPTION:

Run-time errors arise from design faults, coding mistakes, hardware failures, and many other sources. Although you cannot anticipate all possible errors, you can plan to handle certain kinds of errors meaningful to your PL/SQL program. With many programming languages, unless you disable error checking, a run-time error such as stack overflow or division by zero stops normal processing and returns control to the operating system. With PL/SQL, a mechanism called exception handling lets you "bulletproof" your program so that it can continue operating in the presence of errors. In PL/SQL, a warning or error condition is called an exception. Exceptions can be internally defined (by the run-time system) or user defined. Examples of internally defined exceptions include division by zero and out of memory. Some

common internal exceptions have predefined names, such as ZERO_DIVIDE and STORAGE_ERROR. The other internal exceptions can be given names. You can define exceptions of your own in the declarative part of any PL/SQL block, subprogram, or package. For example, you might define an exception named insufficient_funds to flag overdrawn bank accounts. Unlike internal exceptions, user-defined exceptions must be given names. When an error occurs, an exception is raised. That is, normal execution stops and control transfers to the exceptionhandling part of your PL/SQL block or subprogram. Internal exceptions are raised implicitly (automatically) by the run-time system. User-defined exceptions must be raised explicitly by RAISE statements, which can also raise predefined exceptions. To handle raised exceptions, you write separate routines called exception handlers. After an exception handler runs, the current block stops executing and the enclosing block resumes with the next statement. If there is no enclosing block, control returns to the host environment. In the example below, you calculate and store a price-to-earnings ratio for a company with ticker symbol XYZ. If the company has zero earnings, the predefined exception ZERO_DIVIDE is raised. This stops normal execution of the block and transfers control to the exception handlers. The optional OTHERS handler catches all exceptions that the block does not name specifically.
DECLARE pe_ratio NUMBER(3,1); BEGIN SELECT price / earnings INTO pe_ratio FROM stocks WHERE symbol = 'XYZ'; -- might cause division-by-zero error INSERT INTO stats (symbol, ratio) VALUES ('XYZ', pe_ratio); COMMIT; EXCEPTION -- exception handlers begin WHEN ZERO_DIVIDE THEN -- handles 'division by zero' error INSERT INTO stats (symbol, ratio) VALUES ('XYZ', NULL); COMMIT; ... WHEN OTHERS THEN -- handles all other errors ROLLBACK; END; -- exception handlers and block end here

The last example illustrates exception handling, not the effective use of INSERT statements. For example, a better way to do the insert follows:
INSERT INTO stats (symbol, ratio) SELECT symbol, DECODE(earnings, 0, NULL, price / earnings) FROM stocks WHERE symbol = 'XYZ';

In this example, a subquery supplies values to the INSERT statement. If earnings are zero, the function DECODE returns a null. Otherwise, DECODE returns the price-to-earnings ratio.

Advantages of Exceptions
Using exceptions for error handling has several advantages. Without exception handling, every time you issue a command, you must check for execution errors:
BEGIN SELECT ... -- check for 'no data found' error SELECT ... -- check for 'no data found' error SELECT ...

-- check for 'no data found' error

Error processing is not clearly separated from normal processing; nor is it robust. If you neglect to code a check, the error goes undetected and is likely to cause other, seemingly unrelated errors. With exceptions, you can handle errors conveniently without the need to code multiple checks, as follows:
BEGIN SELECT ... SELECT ... SELECT ... ... EXCEPTION WHEN NO_DATA_FOUND THEN

-- catches all 'no data found' errors

Exceptions improve readability by letting you isolate error-handling routines. The primary algorithm is not obscured by error recovery algorithms. Exceptions also improve reliability. You need not worry about checking for an error at every point it might occur. Just add an exception handler to your PL/SQL block. If the exception is ever raised in that block (or any sub-block), you can be sure it will be handled.

Predefined Exceptions
An internal exception is raised implicitly whenever your PL/SQL program violates an Oracle rule or exceeds a system-dependent limit. Every Oracle error has a number, but exceptions must be handled by name. So, PL/SQL predefines some common Oracle errors as exceptions. For example, PL/SQL raises the predefined exception NO_DATA_FOUND if a SELECT INTO statement returns no rows. To handle other Oracle errors, you can use the OTHERS handler. The functions SQLCODE and SQLERRM are especially useful in the OTHERS handler because they return the Oracle error code and message text. Alternatively, you can use the pragma EXCEPTION_INIT to associate exception names with Oracle error codes. PL/SQL declares predefined exceptions globally in package STANDARD, which defines the PL/SQL environment. So, you need not declare them yourself. You can write handlers for predefined exceptions using the names shown in the list below. Also shown are the corresponding Oracle error codes and SQLCODE return values. EXCEPTION
ACCESS_INTO_NULL COLLECTION_IS_NULL CURSOR_ALREADY_OPEN DUP_VAL_ON_INDEX INVALID_CURSOR INVALID_NUMBER LOGIN_DENIED

ORACLE ERROR
ORA-06530 ORA-06531 ORA-06511 ORA-00001 ORA-01001 ORA-01722 ORA-01017

SQLCODE VALUE
-6530 -6531 -6511 -1 -1001 -1722 -1017

EXCEPTION
NO_DATA_FOUND NOT_LOGGED_ON PROGRAM_ERROR ROWTYPE_MISMATCH SELF_IS_NULL STORAGE_ERROR SUBSCRIPT_BEYOND_COUNT SUBSCRIPT_OUTSIDE_LIMIT SYS_INVALID_ROWID TIMEOUT_ON_RESOURCE TOO_MANY_ROWS VALUE_ERROR ZERO_DIVIDE

ORACLE ERROR
ORA-01403 ORA-01012 ORA-06501 ORA-06504 ORA-30625 ORA-06500 ORA-06533 ORA-06532 ORA-01410 ORA-00051 ORA-01422 ORA-06502 ORA-01476

SQLCODE VALUE
+100 -1012 -6501 -6504 -30625 -6500 -6533 -6532 -1410 -51 -1422 -6502 -1476

Brief descriptions of the predefined exceptions follow: EXCEPTION


ACCESS_INTO_NULL

RAISED WHEN ... Your program attempts to assign values to the attributes of an uninitialized (atomically null) object. Your program attempts to apply collection methods other than EXISTS to an uninitialized (atomically null) nested table or varray, or the program attempts to assign values to the elements of an uninitialized nested table or varray. Your program attempts to open an already open cursor. A cursor must be closed before it can be reopened. A cursor FOR loop automatically opens the cursor to which it refers. So, your program cannot open that cursor inside the loop.

COLLECTION_IS_NULL

CURSOR_ALREADY_OPEN

EXCEPTION
DUP_VAL_ON_INDEX

RAISED WHEN ... Your program attempts to store duplicate values in a database column that is constrained by a unique index. Your program attempts an illegal cursor operation such as closing an unopened cursor.

INVALID_CURSOR

INVALID_NUMBER

In a SQL statement, the conversion of a character string into a number fails because the string does not represent a valid number. (In procedural statements, VALUE_ERROR is raised.) This exception is also raised when the LIMIT-clause expression in a bulk FETCH statement does not evaluate to a positive number. Your program attempts to log on to Oracle with an invalid username and/or password. A SELECT INTO statement returns no rows, or your program references a deleted element in a nested table or an uninitialized element in an index-by table. SQL aggregate functions such as AVG and SUM always return a value or a null. So, a SELECT INTO statement that calls an aggregate function never raises NO_DATA_FOUND. The FETCH statement is expected to return no rows eventually, so when that happens, no exception is raised. Your program issues a database call without being connected to Oracle. PL/SQL has an internal problem. The host cursor variable and PL/SQL cursor variable involved in an assignment have incompatible return types. For example, when an open host cursor variable is passed to a stored subprogram, the return types of the actual and formal parameters must be compatible. Your program attempts to call a MEMBER method on a null instance. That is, the built-in parameter SELF (which is always the first parameter passed to a MEMBER method) is null. PL/SQL runs out of memory or memory has been corrupted. Your program references a nested table or varray element using an index number larger than the number of elements in the collection. Your program references a nested table or varray element using an index number (-1 for example) that is outside the legal range. The conversion of a character string into a universal rowid fails because the character string does not represent a valid rowid. A time-out occurs while Oracle is waiting for a resource.

LOGIN_DENIED NO_DATA_FOUND

NOT_LOGGED_ON PROGRAM_ERROR ROWTYPE_MISMATCH

SELF_IS_NULL

STORAGE_ERROR SUBSCRIPT_BEYOND_COUNT

SUBSCRIPT_OUTSIDE_LIMIT

SYS_INVALID_ROWID

TIMEOUT_ON_RESOURCE

EXCEPTION
TOO_MANY_ROWS VALUE_ERROR

RAISED WHEN ... A SELECT INTO statement returns more than one row. An arithmetic, conversion, truncation, or size-constraint error occurs. For example, when your program selects a column value into a character variable, if the value is longer than the declared length of the variable, PL/SQL aborts the assignment and raises VALUE_ERROR. In procedural statements, VALUE_ERROR is raised if the conversion of a character string into a number fails. (In SQL statements, INVALID_NUMBER is raised.) Your program attempts to divide a number by zero.

ZERO_DIVIDE

User-Defined Exceptions
PL/SQL lets you define exceptions of your own. Unlike predefined exceptions, user-defined exceptions must be declared and must be raised explicitly by RAISE statements.

Declaring Exceptions
Exceptions can be declared only in the declarative part of a PL/SQL block, subprogram, or package. You declare an exception by introducing its name, followed by the keyword EXCEPTION. In the following example, you declare an exception named past_due:
DECLARE past_due EXCEPTION;

Exception and variable declarations are similar. But remember, an exception is an error condition, not a data item. Unlike variables, exceptions cannot appear in assignment statements or SQL statements. However, the same scope rules apply to variables and exceptions.

Scope Rules
You cannot declare an exception twice in the same block. You can, however, declare the same exception in two different blocks. Exceptions declared in a block are considered local to that block and global to all its sub-blocks. Because a block can reference only local or global exceptions, enclosing blocks cannot reference exceptions declared in a sub-block. If you redeclare a global exception in a sub-block, the local declaration prevails. So, the sub-block cannot reference the global exception unless it was declared in a labeled block, in which case the following syntax is valid:
block_label.exception_name

The following example illustrates the scope rules:


DECLARE past_due EXCEPTION; acct_num NUMBER; BEGIN

DECLARE ---------- sub-block begins past_due EXCEPTION; -- this declaration prevails acct_num NUMBER; BEGIN ... IF ... THEN RAISE past_due; -- this is not handled END IF; END; ------------- sub-block ends EXCEPTION WHEN past_due THEN -- does not handle RAISEd exception ... END;

The nclosing block does not handle the raised exception because the declaration of past_due in the sub-block prevails. Though they share the same name, the two past_due exceptions are different, just as the two acct_num variables share the same name but are different variables. Therefore, the RAISE statement and the WHEN clause refer to different exceptions. To have the enclosing block handle the raised exception, you must remove its declaration from the sub-block or define an OTHERS handler.

PRAGMA: A pragma exception is a directive to the comiler ,rather than piece of executable code even though a program statement looks like executable code and appear in a program (sucb as pl/sql code) it is not actually executed and doest appear as a part of the execution code of that block . It gives instruction to the compiler. A pragma is a compiler directive, which can be thought of as a parenthetical remark to the compiler. Pragmas (also called pseudoinstructions) are processed at compile time, not at run time PRAGMA EXCEPTION_INIT: There ara many errors and only most common gives a name NO_DATA_FOUND ,ZERO_DIVIDE. Any that one not named will still raise an exception flag and transfer control to the exception block but they will be caught by others rather than by Name. Name to other Oracle error no Exception must allow you to do this pragma In PL/SQL, the pragma EXCEPTION_INIT tells the compiler to associate an exception name with an Oracle error number. That allows you to refer to any internal exception by name and to write a specific handler for it. You code the pragma EXCEPTION_INIT in the declarative part of a PL/SQL block, subprogram, or package using the syntax
PRAGMA EXCEPTION_INIT(exception_name, Oracle_error_number);

where exception_name is the name of a previously declared exception. The pragma must appear somewhere after the exception declaration in the same declarative section, as shown in the following example:
DECLARE deadlock_detected EXCEPTION; PRAGMA EXCEPTION_INIT(deadlock_detected, -60); BEGIN ... EXCEPTION WHEN deadlock_detected THEN -- handle the error END;

--

Managing Cursors
PL/SQL uses two types of cursors: implicit and explicit. PL/SQL declares a cursor implicitly for all SQL data manipulation statements, including queries that return only one row. However, for queries that return more than one row, you must declare an explicit cursor, use a cursor FOR loop, or use the BULK COLLECT clause. Oracle implicitly opens a cursor to process each SQL statement not associated with an explicitly declared cursor. You can refer to the most recent implicit cursor as the SQL cursor. Although you cannot use the OPEN, FETCH, and CLOSE statements to control the SQL cursor, you can use cursor attributes to get information about the most recently executed SQL statement Implicit cursor attributes return information about the execution of an INSERT, UPDATE, DELETE, or SELECT INTO statement. The values of the cursor attributes always refer to the most recently executed SQL statement. Before Oracle opens the SQL cursor, the implicit cursor attributes yield NULL.

Explicit Cursors
The set of rows returned by a query can consist of zero, one, or multiple rows, depending on how many rows meet your search criteria. When a query returns multiple rows, you can explicitly declare a cursor to process the rows. Moreover, you can declare a cursor in the declarative part of any PL/SQL block, subprogram, or package. You use three commands to control a cursor: OPEN, FETCH, and CLOSE. First, you initialize the cursor with the OPEN statement, which identifies the result set. Then, you can execute FETCH repeatedly until all rows have been retrieved, or you can use the BULK COLLECT clause to fetch all rows at once. When the last row has been processed, you release the cursor with the CLOSE statement. You can process several queries in parallel by declaring and opening multiple cursors. Declaring a Cursor Forward references are not allowed in PL/SQL. So, you must declare a cursor before referencing it in other statements. When you declare a cursor, you name it and associate it with a specific query using the syntax
CURSOR cursor_name [(parameter[, parameter]...)] [RETURN return_type] IS select_statement;

where return_type must represent a record or a row in a database table, and parameter stands for the following syntax:
cursor_parameter_name [IN] datatype [{:= | DEFAULT} expression]

For example, you might declare cursors named c1 and c2, as follows:
DECLARE CURSOR c1 IS SELECT empno, ename, job, sal FROM emp WHERE sal > 2000; CURSOR c2 RETURN dept%ROWTYPE IS SELECT * FROM dept WHERE deptno = 10;

The cursor name is an undeclared identifier, not the name of a PL/SQL variable. You cannot assign values to a cursor name or use it in an expression. However, cursors and variables follow the same scoping rules. Naming cursors after database tables is allowed but not recommended. A cursor can take parameters, which can appear in the associated query wherever constants can appear. The formal parameters of a cursor must be IN parameters. Therefore, they cannot return values to actual parameters. Also, you cannot impose the constraint NOT NULL on a cursor parameter. As the example below shows, you can initialize cursor parameters to default values. That way, you can pass different numbers of actual parameters to a cursor, accepting or overriding the default values as you please. Also, you can add new formal parameters without having to change every reference to the cursor.
DECLARE CURSOR c1 (low INTEGER DEFAULT 0, high INTEGER DEFAULT 99) IS SELECT ...

The scope of cursor parameters is local to the cursor, meaning that they can be referenced only within the query specified in the cursor declaration. The values of cursor parameters are used by the associated query when the cursor is opened. Opening a Cursor Opening the cursor executes the query and identifies the result set, which consists of all rows that meet the query search criteria. For cursors declared using the FOR UPDATE clause, the OPEN statement also locks those rows. An example of the OPEN statement follows:
DECLARE CURSOR c1 IS SELECT ename, job FROM emp WHERE sal < 3000; ... BEGIN OPEN c1; ... END;

Rows in the result set are not retrieved when the OPEN statement is executed. Rather, the FETCH statement retrieves the rows. Passing Cursor Parameters You use the OPEN statement to pass parameters to a cursor. Unless you want to accept default values, each formal parameter in the cursor declaration must have a corresponding actual parameter in the OPEN statement. For example, given the cursor declaration
DECLARE emp_name emp.ename%TYPE; salary emp.sal%TYPE; CURSOR c1 (name VARCHAR2, salary NUMBER) IS SELECT ...

any of the following statements opens the cursor:


OPEN c1(emp_name, 3000); OPEN c1('ATTLEY', 1500); OPEN c1(emp_name, salary);

In the last example, when the identifier salary is used in the cursor declaration, it refers to the formal parameter. But, when it is used in the OPEN statement, it refers to the PL/SQL variable. To avoid confusion, use unique identifiers. Formal parameters declared with a default value need not have a corresponding actual parameter. They can simply assume their default values when the OPEN statement is executed. You can associate the actual parameters in an OPEN statement with the formal parameters in a cursor declaration using positional or named notation. (See "Positional versus Named Notation".) The datatypes of each actual parameter and its corresponding formal parameter must be compatible. Fetching with a Cursor Unless you use the BULK COLLECT clause (discussed in the next section), the FETCH statement retrieves the rows in the result set one at a time. After each fetch, the cursor advances to the next row in the result set. An example follows:
FETCH c1 INTO my_empno, my_ename, my_deptno;

For each column value returned by the query associated with the cursor, there must be a corresponding, typecompatible variable in the INTO list. Typically, you use the FETCH statement in the following way:
LOOP FETCH c1 INTO my_record; EXIT WHEN c1%NOTFOUND; -- process data record END LOOP;

The query can reference PL/SQL variables within its scope. However, any variables in the query are evaluated only when the cursor is opened. In the following example, each retrieved salary is multiplied by 2, even though factor is incremented after every fetch:
DECLARE my_sal emp.sal%TYPE; my_job emp.job%TYPE; factor INTEGER := 2; CURSOR c1 IS SELECT factor*sal FROM emp WHERE job = my_job; BEGIN ... OPEN c1; -- here factor equals 2 LOOP FETCH c1 INTO my_sal; EXIT WHEN c1%NOTFOUND; factor := factor + 1; -- does not affect FETCH END LOOP; END;

To change the result set or the values of variables in the query, you must close and reopen the cursor with the input variables set to their new values. However, you can use a different INTO list on separate fetches with the same cursor. Each fetch retrieves another row and assigns values to the target variables, as the following example shows: A user-written function can now be called from a SQL statement without any compile-time checking of its purity: PRAGMA RESTRICT_REFERENCES is no longer required on functions called from SQL statements.

remains available as a means of asking the PL/SQL compiler to verify that a function has only the side effects that you expect. SQL statements, package variable accesses, or calls to functions that violate the declared restrictions will continue to raise PL/SQL compilation errors to help you isolate the code that has unintended effects.
PRAGMA RESTRICT_REFERENCES

Because Oracle no longer requires that the pragma on functions called from SQL statements, different applications may choose different style standards on whether and where to use PRAGMA RESTRICT REFERENCES. An existing PL/SQL application will most likely want to continue using the pragma even on new functionality, to ease integration with the existing code. A newly created Java application will most likely not want to use the pragma at all, because the Java compiler does not have the functionality to assist in isolating unintended effects

Using PRAGMA RESTRICT_REFERENCES To assert the purity level, code the pragma RESTRICT_REFERENCES in the package specification (not in the package body). The pragma must follow the function declaration, but it does not need to follow it immediately. Only one pragma can reference a given function declaration. To code the pragma RESTRICT_REFERENCES, use the following syntax:
PRAGMA RESTRICT_REFERENCES ( Function_name, WNDS [, WNPS] [, RNDS] [, RNPS] [, TRUST] );

Where: Writes no database state (does not modify database tables). Reads no database state (does not query database tables). Writes no package state (does not change the values of packaged variables). Reads no package state (does not reference the values of packaged variables). Allows easy calling from functions that do have RESTRICT_REFERENCES declarations to those that do not.

WNDS RNDS WNPS RNPS TRUST

You can pass the arguments in any order. If any SQL statement inside the function body violates a rule, then you get an error when the statement is parsed. In the example below, the function compound neither reads nor writes database or package state; therefore, you can assert the maximum purity level. Always assert the highest purity level that a function allows. That way, the PL/SQL compiler never rejects the function unnecessarily. NOTE: You may need to set up the following data structures for certain examples to work:
CREATE TABLE Accts ( Yrs NUMBER Amt NUMBER Acctno NUMBER Rte NUMBER);

CREATE PACKAGE Finance AS -- package specification FUNCTION Compound (Years IN NUMBER, Amount IN NUMBER, Rate IN NUMBER) RETURN NUMBER; PRAGMA RESTRICT_REFERENCES (Compound, WNDS, WNPS, RNDS, RNPS); END Finance; CREATE PACKAGE BODY Finance AS --package body FUNCTION Compound (Years IN NUMBER, Amount IN NUMBER, Rate IN NUMBER) RETURN NUMBER IS BEGIN RETURN Amount * POWER((Rate / 100) + 1, Years); END Compound; -- no pragma in package body END Finance;

Later, you might call compound from a PL/SQL block, as follows:


DECLARE Interest NUMBER; Acct_id NUMBER; BEGIN SELECT Finance.Compound(Yrs, Amt, Rte) -- function call INTO Interest FROM Accounts WHERE Acctno = Acct_id; User_exit in reports: A user exit is a program that you write and then link into the Report Builder executable or user exit DLL files. You build user exits when you want to pass control from Report Builder to a program you have written, which performs some function, and then returns control to Report Builder. You can write the following types of user exits: n n n ORACLE Precompiler user exits OCI (ORACLE Call Interface) user exits non-ORACLE user exits

You can also write a user exit that combines both the ORACLE Precompiler interface and the OCI. User exits can perform the following tasks: n n n n n perform complex data manipulation pass data to Report Builder from operating system text files manipulate LONG RAW data support PL/SQL blocks control real time devices, such as a printer or a robot

You can use user exits for other tasks, such as mathematical processing. However, Oracle Corporation recommends that you perform such tasks with PL/SQL within Report Builder. Usage Notes

n Not all types of user exits can perform all of the described tasks. accomplish most of these tasks only with ORACLE Precompiler user exits.

You can

n Some details of implementing user exits are specific to each operating system. For more information on the exact steps you need to follow, see the Developer/2000 installation instructions for your operating system. /* ** ** ** ** */ /* ** ** */ Suppose you want your report to create a table named CHECK just before the Runtime Parameter Form is displayed. Because CREATE TABLE is a SQL DDL statement (and PL/SQL cannot perform DDL statements), you need to use SRW.DO_SQL. Therefore, your PL/SQL could look like this in the Before Form trigger: Additional Information: If you use a table created in this way for your report output, the table must exist before you create your query in the data model. Otherwise, Report Builder would not be able to parse your query.

CREATING A TABLE IN REPORTS: USING SRW.DO_SQL(STRING); FUNCTION CREATETAB RETURN BOOLEAN IS BEGIN SRW.DO_SQL('CREATE TABLE CHECK (EMPNO NUMBER NOT NULL PRIMARY KEY, SAL NUMBER (10,2)) PCTFREE 5 PCTUSED 75'); RETURN(TRUE); EXCEPTION WHEN SRW.DO_SQL_FAILURE THEN SRW.MESSAGE(100, 'ERROR WHILE CREATING CHECK TABLE.'); SRW.MESSAGE(50, 'REPORT WAS STOPPED BEFORE THE RUNTIME PARAMETER FORM.'); RAISE SRW.PROGRAM_ABORT; END; About the call interface A call interface is a set of standard procedures that you can call in your 3GL programs. Report Builder is shipped with several such procedures (written in C)--one for each of the following executables: Executable Procedure Names R30CONV RWCCON, RW2CON R30RUN (bit-mapped) RWCRRB, RW2RRB R30RUN (character mode) RWCRUN, RW2RUN R30DES (bit-mapped) RWCSRB, RW2SRB For example, assume that you have written a Pro*FORTRAN program and you want it to run an Report Builder report (using the character- mode R30RUN executable). To do so, you add a RWCRUN or RW2RUN procedure call to your program. (Details on which of the two procedures to use is discussed in the syntax portion of this chapter.) For a complete example of the call interface, look in $ORACLE_HOME/REPORT30/OCI/Samples. should also read the file named oci_info.txt in $ORACLE_HOME/REPORT30/OCI. Usage Notes n To use the call interface, your program must be written with one of the ORACLE Programmatic Interface host languages (Ada, C, COBOL, FORTRAN, Pascal, or PL/l). When you invoke R30CONV with the call interface, you will get whichever executable (bit-mapped or character-mode) is shipped for your platform. n In Oracle Reports 2.5, there were two procedures named RWCSRV and RW2SRV. Builder 3.0, you should replace these procedures by using RWCRRB and RW2RRB with BACKGROUND=YES. REPORT TRIGGERS: In Report You

Report triggers enable you to execute PL/SQL functions at specific times during the execution and formatting of your report. Using the conditional processing capabilities of PL/SQL for these triggers, you can do things such as customize the formatting of your report, perform initialization tasks, and access the database. To create or modify a report trigger, use Report Triggers in the Object Navigator. Report triggers must explicitly return TRUE or FALSE.

The list below shows the order of events when a report is executed. 1 2 3 4 5 6 7 Before Parameter Form trigger is fired. Runtime Parameter Form appears (if not suppressed). After Parameter Form trigger is fired (unless the user cancels from the Runtime Parameter Form). Report is "compiled." Queries are parsed. Before Report trigger is fired. SET TRANSACTION READONLY is executed (if specified via the READONLY argument or setting).

8 The report is executed and the Between Pages trigger fires for each page except the last one. (Note that data can be fetched at any time while the report is being formatted.) COMMITs can occur during this time due to any of the following--user exit with DDL, SRW.DO_SQL with DDL, or if ONFAILURE=COMMIT, and the report fails. 9 10 COMMIT is executed (if READONLY is specified) to end the transaction. After Report trigger is fired.

11 COMMIT/ROLLBACK/NOACTION is executed based on what was specified via the ONSUCCESS argument or setting. Cautions n In steps 4 through 9, avoid DDL statements that would modify the tables on which the report is based. Step 3 takes a snapshot of the tables and the snapshot must remain valid throughout the execution of the report. In steps 7 through 9, avoid DML statements that would modify the contents of the tables on which the report is based. Queries may be executed in any order, which makes DML statements unreliable (unless performed on tables not used by the report). n If you specify READONLY, you should avoid DDL altogether. When you execute a DDL statement (e.g., via SRW.DO_SQL or a user exit), a COMMIT is automatically issued. If you are using READONLY, this will prematurely end the transaction begun by SET TRANSACTION READONLY. Description The Between Pages trigger fires before each page of the report is formatted, except the very first page. This trigger can be used for customized page formatting. In the Runtime Previewer or Live Previewer, this trigger only fires the first time that you go to a page. If you subsequently return to the page, the trigger does not fire again. Definition Level report On Failure Displays an error message when you try to go to the page for which the trigger returned FALSE. The pages subsequent to the page that returned FALSE are not formatted. If the trigger returns FALSE on the last page, nothing

happens because the report is done formatting. The Between Pages trigger does not fire before the first page. If the trigger returns FALSE on the first page, the first page is displayed, but, if you try to go to the second page, an error message is displayed. A placeholder is a column for which you set the datatype and value in PL/SQL that you define. You can set the value of a placeholder column in the following places: n n the Before Report Trigger, if the placeholder is a report-level column a report-level formula column, if the placeholder is a report-level column

n a formula in the placeholder's group or a group below it (the value is set once for each record of the group) A formula column performs a user-defined computation on another column(s) data. Formulas are PL/SQL functions that populate formula or placeholder columns. You can access the PL/SQL for formulas from the Object Navigator, the PL/SQL Editor, or the Property Palette (i.e., the PL/SQL Formula property). A column of datatype Number can only have a formula that returns a value of datatype NUMBER. A column of Datatype Date can only have a formula that returns a value of datatype DATE. A column of Datatype Character can only have a formula that returns a value of datatype CHARACTER, VARCHAR, or VARCHAR2. A summary column performs a computation on another column's data. Using the Report Wizard or Data Wizard, you can create the following summaries: sum, average, count, minimum, maximum, % total. You can also create a summary column manually in the Data Model view, and use the Property Palette to create the following additional summaries: first, last, standard deviation, variance. Note: For group reports, the Report Wizard and Data Wizard create n summary fields in the data model for each summary column you define: one at each group level above the column being summarized, and one at the report level (for example, if a report is grouped by division, and further grouped by department, then a summary column on salary would create fields for the sum of salaries for each division and each department group, and the sum of all salaries). OTHER TRIGGERS: FORMAT TRIGGER,ACTION TRIGGER,VALIDATE TRIGGER Anchors are used to determine the vertical and horizontal positioning of a child object relative to its parent. The end of the anchor with a symbol on it is attached to the parent object.. In the Layout Model view, click in the tool palette. 2 Click an edge of the child object and double-click an edge of the parent object.

A line is drawn from the child to the parent. A small box appears at the end of the line that is attached to the parent object. Suppose you want to horizontally center a field within a repeating frame that has its Horizontal Elasticity set to Variable. You also want the field to be a fixed distance from the top edge of the repeating frame. Since you don't know how large or small the formatted repeating frame will be, you need to use anchors to center the field. EXPAMPLE: To center the field horizontally within the repeating frame do the following:

n Place the field inside the repeating frame such that the x coordinate of the center of the top of the field is the same as the x coordinate of the center of the top of the repeating frame. See the figure below. n Draw an anchor from the center of the top of the field to the center of the top of the repeating frame. Tip

The field will now be centered horizontally within the repeating frame.

MATRIX REPORT : QUERY can be 1 group must be 4. Property class: A property class is a named object that contains a list of properties and their settings. Once you create a property class you can base other objects on it. An object based on a property class can inherit the setting of any property in the class that makes sense for that object. Property class inheritance is an instance of subclassing. Conceptually, you can consider a property class as a universal subclassing parent. There can be any number of properties in a property class, and the properties in a class can apply to different types of objects. For example, a property class might contain some properties that are common to all types of items, some that apply only to text items, and some that apply only to check boxes. When you base an object on a property class, you have complete control over which properties the object should inherit from the class, and which should be overridden locally. Property classes are separate objects, and, as such, can be copied between modules as needed. Perhaps more importantly, property classes can be subclassed in any number of modules. Property classes are similar to named visual attributes, but there are important differences you should be aware of: n Named visual attributes define only font, color, and pattern attributes; property classes can contain these and any other properties. n You can change the appearance of objects at runtime by changing the named visual attribute programmatically; property class assignment cannot be changed programmatically. n When an object is inheriting from both a property class and a named visual attribute, the named visual attribute settings take precedence, and any visual attribute properties in the class are ignored. Form Builder provides four types of canvases, all of which can be displayed in the same window at runtime. A canvas' type defines how Form Builder will display it in the window to which it is assigned. When you create a canvas, you specify its type by setting the Canvas Type property. The four canvas types are: n n n n Content Stacked Tab Toolbar

Content Canvas The most common canvas type is the content canvas (the default type). A content canvas is the "base" view that occupies the entire content pane of the window in which it is displayed. You must define at least one content canvas for each window you create.

Stacked Canvas A stacked canvas is displayed atopor stacked onthe content canvas assigned to the current window. Stacked canvases obscure some part of the underlying content canvas, and often are shown and hidden programmatically. You can display more than one stacked canvas in a window at the same time.

Tab Canvas A tab canvasmade up of one or more tab pagesallows you to group and display a large amount of related information on a single dynamic Form Builder canvas object. Like stacked canvases, tab canvases are displayed on top of a content canvas, partly obscuring it. Tab pages (that collectively comprise the tab canvas) each display a subset of the information displayed on the entire tab canvas. Toolbar Canvas A toolbar canvas often is used to create toolbars for individual windows. You can create two types of toolbar canvases: horizontal or vertical. Horizontal toolbar canvases are displayed at the top of a window, just under its menu bar, while vertical toolbars are displayed along the far left edge of a window.

You might also like