Showing posts with label Forms. Show all posts
Showing posts with label Forms. Show all posts

A Basic Tutorial on Oracle9i Forms and Reports

Covering Developer version 9i for Windows NT/2000/XP By Richard Holowczak

This tutorial introduces the Oracle9i Developer Suite Release 2 (August, 2002) that includes Oracle Forms 9.0 and Oracle Reports 9.0. The main objectives are to demonstrate and provide hands-on instructions on creating and modifying data entry and query forms in various configurations, reports and graphics.

Caveats: Please note that Oracle tends to change things like menu items, prompts and other small things between each major (certainly) and often minor release. Depending on the exact release of Oracle9i Developer Suite you have, you may find some small discrepencies between what is shown in this tutorial and what you see on your screen.

Prerequisites
Before following this tutorial, a student must have a valid user account in an Oracle server or a local installation of an Oracle database. Contact your DBA or systems administrator to learn the details of how Oracle server is set up in your organization.

If you have a local instance of the Oracle database, please do not use the SYSTEM (DBA) account to practice development. There is a good chance you can corrupt the entire database by mistake. You are much better off making use of the SCOTT/TIGER schema or (even better) creating a separate user (schema) for this tutorial work and for practicing.

One more word of caution. Oracle has designed Oracle9i as a three tier architecture. This means that the database (Oracle9i server) should run on one server, the application Server (oracle9i Application Server or Oracle9iAS Containers for Java (OC4J) server as used here) runs on a second server and the client application (written in Oracle Forms and Reports for example) runs on a third machine.

Contents




About the Author: Richard Holowczak is an Associate Professor of Computer Information Systems at the Zicklin School of Business in Baruch College, City University of New York.

Multipurpose code in Oracle and Oracle Forms

Author: Steve Callan, stevencallan@hotmail.com

When Oracle gave up the ghost on client-server Forms several years ago, one of the built-in's that went by the wayside was related to feeding parameters into an alert message function. If you handled errors or missing input (as you should), part of the Forms migration process involved changing the built-in from the 6i version to the 9i version. A complex application can have thousands of alert messages, and a major application (Forms, that is) change can require thousands of changes. Making a change like that was really bad form on Oracle's part.

On the other hand, as a DBA and developer using PL/SQL, how many times have you written DBMS_OUTPUT.PUT_LINE('whatever')? Having to write or type DBMS_OUTPUT.PUT_LINE gets to be very tiresome, so wouldn't it be nice to have a shorter piece of code along the lines of a handy built-in? Maybe not so much as foresight, but due more to good luck or realizing the same thing had to be typed over and over, crafty Forms developers made their own built-in, in the form of a procedure used to generate an alert message. That same construct can be used in your everyday PL/SQL code. In fact, you can create a small message library to take care of many types of output messages. Let's take a look at some of these possibilities.

A Simple Alert Message Procedure

Just as the section heading says, this first method is quite simple. Suppose you have a frequent need to output the number of records updated by a procedure, function, or block of code. Let's say the number of rows updated was 46. A simple “am(46);” based on the procedure below generates the output you're looking for.

CREATE OR REPLACE procedure am (msg number) as
begin
dbms_output.put_line('Records updated: '||msg);
end;
/

An alternative version can handle strings, so a call to “ams('your message here');” significantly shortens your typing/number of keystrokes. When debugging or troubleshooting code/logic, having an easily accessible “built-in” is invaluable for outputting stubs or “where am I in the code” statements. Location reporting can confirm, for example, where you were branched in an IF-THEN-ELSE statement. If your problem code has lots of calls to other objects (procedures, functions, etc.), echoing out state information such as “calling function X” and “returned from function X” can confirm process flow. Finally, another use case involves reporting values. You can report or track how (and even where) a variable has its value changed.

Building an Alert Message Library

The degree of complexity or flexibility of your message library is, of course, entirely up to you. If your (output) messaging needs are simple, then keep the procedure simple. More precisely, keep the number of separate procedures to a minimum. Two simple ones, named ams and amn can be used to output messages based on string and numeric input.

If the text component of the output you want needs to vary based on what just took place, such as the outcome of a DML statement, then you may want to have a set of three built-ins (one for inserted, updated and deleted). Maybe you want to specify the type or reason of deletion. Let's say that one step in a batch processing job is to count the number of duplicate records. An output of “Records counted: 46” is useful, but then in that vein, “Duplicates counted: 46” would appear to be even more telling. So let's add two more built-ins.

Just like that, we're up to at least six separate procedures. Hints of manageability issues should be apparent now. We were looking for something simple, but at the same time, robust. There are at least two ways to re-simplify the desired functionality. One way is to make the alert message procedure accept two input parameters, and the other, which is what I'm leading up to, is to package the procedures.

Increase the number of input parameters

Again, if this simpler solution fulfills your needs, there is no need to go further. Create the procedure with two inputs, the first being the message text or base, the second being the outcome, location, state or value. The two input combinations of text/text and text/number can be boiled down to text/text if you (not Oracle) take care of the data type conversion. Do you **have** to do the conversion? No, but to be consistent in what you do, if you cast elsewhere, then cast here. Regardless, the following example shows the flexibility of this first approach.

CREATE OR REPLACE procedure am (msg1 varchar2, msg2 varchar2) as
begin
dbms_output.put_line(msg1||msg2);
end;
/

After compilation, shown below is an example of its use.

SQL> set serveroutput on
SQL> exec am('Here I am',46);
Here I am46

PL/SQL procedure successfully completed.

Well, this output could look better (note the lack of a space between msg1 and msg2 in the output). Great, we're stuck with also having to format one or both message inputs to make the output look nice. However, if nicety is not a concern, then creating messages based on inputs like ('dupes ',46), where you take care of the spacing or formatting, is still pretty simple. Are there any pitfalls with this approach? That depends. What if all you need is msg1 and nothing for msg2? When creating the procedure, allow for msg2 to be null as needed. Obviously, this is not needed for msg1, right?

CREATE OR REPLACE procedure am
(msg1 varchar2, msg2 varchar2 default null) as
begin
dbms_output.put_line(msg1||msg2);
end;
/

Procedure created.

SQL> exec am('Where am I?');
Where am I?

PL/SQL procedure successfully completed.

Increasing the robustness

What if your message is very long, or needs to fit on a page/line of spooled output? Ignoring word wrapping for the time being, a simple way to chop up the text is to substring it appropriately. This situation cries out for recursion, and of course, the best way to understand recursion is to first understand recursion (sorry, old joke). The chopping up process performs a length check, if the remaining string is longer than your cutoff value, make a call to the substring-ing step, and repeat as necessary.

What if the cut takes place in the middle of a word? Okay, remember, this is PL/SQL, not a word processing program/language. In a Forms environment, where the text is going into a text field, you generally get this formatting for free. You do get some formatting functionality via SQL*Plus, but be sure to pick the right type for your needs. Using a series of eight strings of A through J (and a space after J), and setting the linesize low (easier to see the difference between the word wrapping options), the output below is an example of what takes place.

set serveroutput on format word_wrapped
exec am(insert the 8 strings here);
abcdefghij abcdefghij
abcdefghij abcdefghij
abcdefghij abcdefghij
abcdefghij abcdefghij

set serveroutput on format wrapped
exec am(insert the 8 strings here);
abcdefghij abcdefghij abcdefgh
ij abcdefghij abcdefghij abcde
fghij abcdefghij abcdefghij

The object lesson in this example is to take advantage of what is already built in. No need to reinvent the wheel is there? If “FORMAT WORD_WRAPPED” were not available, how would you solve this? The second example shows the straightforward cut referenced by the recursion approach.

Packaging up your library

There's a good example of how to create a base library in O'Reilly's Oracle PL/SQL Developer's Workbook (by Steven Feuerstein, published in 2000), and it takes advantage of overloading. As you may recall from a previous article, overloading allows you to use the same name for a function or procedure (within a package), and Oracle knows which version you're referencing by evaluating the number and types of parameters.

A clever naming convention to use, particularly if you work with Java developers, is to name the package “prt” and the procedures “ln,” so the end result is “prt.ln('your message');.” Java's method of printing a line uses System.out.println(), so you can see why “prt.ln” seems fairly intuitive as to its purpose and function. The examples shown in the book handle text, numeric, date, and Boolean types of input.

CREATE or REPLACE package prt is
Procedure ln (msg in varchar2);
Procedure ln (msg in number);
Procedure ln (msg in date);
Procedure ln (msg in boolean);
END prt;
/

The procedures above can be expanded to include the other examples or cases mentioned earlier. You can still have output with boilerplate text already built in. Just add “Procedure dup(msg in number” to the package and package body, and a call such as “prt.dup(46);” can result in an output of “Duplicates counted: 46.”

In Closing

So what if Oracle Corporation were to one day change/deprecate the DBMS_OUTPUT built-in? How many places in your code base have you used this? The beauty of packaging up this functionality into your own library is that you would only need to update one body of code – that of what is in the package body. The Forms community spent thousands of hours having to update thousands, if not millions, of forms binary files because of how the alert message functionality/specification changed. For DBAs and developers, this should serve as a valuable lesson in learning how to take charge of what Oracle provides out of the box and making something better to suit your own purposes.

Converting to Oracle Forms 10g

In this article we will go through methods to convert an earlier version of Oracle Forms to Oracle Forms 10g Version. Here we are going to discuss a method through batch file provided by Oracle.

 

In the <ORACLE_HOME>\BIN folder there is a batch file named frmplsqlconv.bat. In this batch file it is calling a Java class to search and replace values found in older form for enabling the conversion.

 

The following is the line by which the actual conversion is done:

 

<ORACLE_HOME>\jdk\bin\java -Dsun.java2d.noddraw=true -DCONVERTER_DEFAULTS=<ORACLE_HOME>\forms\converter.properties -DSEARCH_REPLACE_FILE=<ORACLE_HOME>\forms\search_replace.properties oracle.forms.util.wizard.Converter %*

 

The file converter.properties contains some default properties of the converter class. The file search_replace.properties contains strings to be replaced in the new converted version of form.

 

This is the default search and replace functions handled in the search_replace.properties file:

 

###########################################################################

# The set of search and replace strings

# Each of these are in the form SearchString|ReplaceString

# Users can add their own set of search and replace strings at

# the end of this block

###########################################################################

Replace1=ROLLBACK_FORM|CLEAR_FORM(NO_COMMIT,FULL_ROLLBACK)

Replace2=ROLLBACK_NR|CLEAR_FORM(NO_COMMIT,FULL_ROLLBACK)

Replace3=ROLLBACK_RL|CLEAR_FORM(NO_COMMIT,FULL_ROLLBACK)

Replace4=OHOST|HOST

Replace5=MENU_CLEAR_FIELD|CLEAR_ITEM

Replace6=MENU_FAILURE|FORM_FAILURE

Replace7=MENU_MESSAGE|MESSAGE

Replace8=MENU_NEXT_FIELD|NEXT_ITEM

Replace9=MENU_PREVIOUS_FIELD|PREVIOUS_ITEM

Replace10=MENU_SHOW_KEYS|SHOW_KEYS

Replace11=MENU_SUCCESS|FORM_SUCCESS

Replace12=OS_COMMAND|HOST

Replace13=OS_COMMAND1|HOST

Replace14=:UN|GET_APPLICATION_PROPERTY(USERNAME)

Replace15=:PW|GET_APPLICATION_PROPERTY(PASSWORD)

Replace16=:LN|GET_APPLICATION_PROPERTY(USER_NLS_LANG)

Replace17=:AD|GET_FORM_PROPERTY(NAME_IN('SYSTEM.CURRENT_FORM'),FILE_NAME)

Replace18=:SO|:SYSTEM.TRIGGER_MENUOPTION

Replace19=RUN_PRODUCT|RP2RRO.RP2RRO_RUN_PRODUCT

Replace20=CHANGE_ALERT_MESSAGE|SET_ALERT_PROPERTY

Replace21=BREAK|DEBUG.SUSPEND

Replace22=DISABLE_ITEM|ENABLEDISABLEITEM.REPLACEDISABLEMENU

Replace23=ENABLE_ITEM|ENABLEDISABLEITEM.REPLACEENABLEMENU

 

One can add any other function (user-defined) in this list by specifying ReplaceNN (replace NN with running sequence numbers).

 

There is also an option to provide group of built-ins for which warnings are to be given by specifying a alternate built-in to use if the occurrence is a Forms procedure. The default section contains the following:

 

WarnOnlyBuiltIn.Message=The String %s was found. If it is an occurrence of the Forms Built-In, It should be replaced with %s.

WarnOnlyBuiltIn.WarnOnly1=CALL|CALL_FORM

 

Then create a batch file with all your old form modules name like:

 

REM Start Compiling

::convert_to_forms10g.bat

cls

Echo Compiling Forms....

for %%f IN (*.fmb) do frmplsqlconv module=%%f userid=xx/xx log=%%forms_conversion.log

for %%f in (*.pll) do frmcmp userid=xx/xx module=%%f module_type=LIBRARY batch=yes window_state=minimize compile_all=yes

for %%f in (*.mmb) do frmcmp userid=xx/xx module=%%f module_type=MENU batch=yes window_state=minimize compile_all=yes

for %%f in (*.mmb) do frmcmp userid=xx/xx module=%%f module_type=FORM batch=yes window_state=minimize parse=YES

for %%f in (*.mmb) do frmcmp userid=xx/xx module=%%f module_type=FORM batch=yes window_state=minimize script=YES

for %%f IN (*.fmb) do frmcmp userid=xx/xx module=%%f batch=yes module_type=form compile_all=yes window_state=minimize

ECHO Finished Conversion...Check for log file for details

How to kill inactive session from Forms

Technology: Oracle Forms 6i, Oracle Database 9i or greater

One of my friend asked how we can kill an inactive session of forms. In an Application server environment this can be attained by modifying none of the application. But as the version is not of our discussion it will not be discussed here.

Here is how we have attained such a result:

We have to use the D2KWUTIL.PLL. In the WHEN-NEW-FORM-INSTANCE trigger provide the following code:
declare
lwindow PLS_INTEGER;
ltimer TIMER;
begin
lwindow := get_window_property(FORMS_MDI_WINDOW,WINDOW_HANDLE);
Win_API_Session.Timeout_Start_Timer(lwindow);
ltimer := Create_Timer('TIMER1',1000,repeat);
end;

In WHEN-TIMER-EXPIRED trigger provide the following code:
begin
if upper(get_application_property(TIMER_NAME)) = 'TIMER1' then
:control.inactive_time := Win_api_session.Timeout_Get_Inactive_Time;
if : control.inactive_time > 120 then
Win_API_Session.timeout_delete_timer;
exit_form (NO_VALIDATE);
end if;
end if;
end;

Control is a block and inactive_timer is a text item. It need not be displayed in any canvas.

Cannot directly access remote package variable or cursor

Have you ever encountered error "Implementation Restriction: 'XX.XX': Cannot directly access remote package variable or cursor" while compiling oracle forms? If yes read below to find a method of creating a generic way of assigning values to variables from oracle forms.

Here in this article we will see how to avoid the error "Cannot directly access remote package variable or cursor" from Oracle forms through an example.

We have created a package for test purposes. The name of the package is testpck. Assume it has a lot of variables, say some 200 and you need to assign values to each of the variables from front-end. One way is to create a procedure which assigns values using a rowtype variable. But in this approach we would be writing unnecessary code to attain the logic.

In this example listed below we have used only one variable in the package specification. The variable name is l_variable. For simplicity of discussion I am restricting the variables of type VARCHAR2. This can be further enhanced to provide a logic for all of the datatypes.

Find below the code for package specification:
create or replace package testpck as
l_variable varchar2(255);

procedure l_set_variable_value(l_variable_name varchar2, l_variable_value varchar2);
end;
/

Find below the code for package body:
create or replace package body testpck as
procedure l_set_variable_value(l_variable_name varchar2, l_variable_value varchar2) as
l_sql varchar2(4000);
begin
l_sql := 'begin testpck.'||l_variable_name ||':='||chr(39)||l_variable_value||chr(39)||'; end;';
execute immediate l_sql;
exception
when others then
dbms_output.put_line(sqlerrm);
end;
end;
/

Now to test this procedure:
begin
testpck.l_set_variable_value('l_variable',
'variables value');
end;
/

That's all. Now you can use this procedure to assign value to any of the variables present in the package specification. If an invalid variable name is passed then the following error will pop out:
ORA-06550: line 1, column 15:
PLS-00302: component 'L_VARIABLE1' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

Traverse through all items in a form

The simple technique of traversing through all items in a form is demonstrated in this article. See below logic for the traversing:

001 start program
002 get first block name;
003 get last block name;
004 go to first block name;
005 assign value of first block name to current block;
006 start loop
007 get first item;
008 get last item;
009 if the loop is running for first time then assign current item's value as first item;
010 print item name;
011
012 if last item is true and current block is not last block
013 go to next block;
014 assign current block's value as new block's name;
015 else if last item is true and current block is last block
016 exit loop;
017 else if current item is not last item
018 go to next item;
019 assign current item's value as new item's name;
020 end if;
021 end loop;
022 end program;

Parameters to Form Runtime

The following are the valid parameters to ifrun60.exe (Forms 6i):

Module - Form Runtime module name
Userid - Login credentials
Term - Oracle Terminal resource file
Debug - Invoke the PL/SQL Debugger
Debug_Messages - Display debugging messages
Keyout - Write Input keystrokes to file
Keyin - Read Input keystrokes from file
Output_File - Write display to file
Interactive - Write display to terminal
Array - Use array SQL Processing
Buffer_Records - Buffer records to temporary file
Logon_screen - Displays the screen to specify logon name
Block_Menu - Display block menu on startup
OptimizeSQL - Optimize V2-Style Trigger-Step SQL Processing
Quiet - Quiet Mode
Statistics - Show statistics
Query_Only - Show forms in query only mode
Help - Show the help screen related to parameters
Options_Screen - Displays options window (Only bitmap mode)
Pecs - Collect PECS data
Window_state - Root window state(Normal, Maximize, Minimize)

Parameters to Form Builder

The following are the valid parameters to ifbld90.exe (Form Builder 9i):

Module Module Name
Userid Database login credentials
Module_type FORM/LIBRARY/MENU
Term Oracle Terminal Resource Mapping File
Help To show all valid parameters to ifbld90

The following are the valid parameters to ifbld60.exe (Form Builder 6i):
Module Module Name
Userid
Database login credentials
Module_type
FORM/LIBRARY/MENU/PECS
Module_Access FILE/DATABASE
Term Oracle Terminal Resource Mapping File
Help To show all valid parameters to ifbld60