
Tuesday, August 25, 2009
Forms Dynamic Audit Program

Thursday, August 13, 2009
Before Starting ( Application Development and Desgin Standards)
1- You Should Comment your Tables and database objects to facilitate the understanding of the database design and reduce the cost of any future modification and facilitates the knowledge requested by any developer or desginer
2- You should comment your columns if needed to be cleared what is this column functionality is . ( if columns are commented , the developer will know in very easy way what this column is designed to , and whic values allowed & which symbol means )
3- Naming Convention for database objects and its attributes should be kept to facilitate the work process and make any common adjustments can be done.( suppose that you keep the naming convention of your tables to be prefixed by 2 letter_ and the table primary key column is composed of your table name without the prefeix and suffixed by _id, you can create a stored procedure that create a sequence and trigger for any new table , so you can save the time and effort by keeping database objects naming conventions )
4- Documentation of the database design is very important for understanding, updating , and maintaining the database design , this document should describe the details of the database design and its functionality and break down ERDs .
5- The development environment must have maintained Templates for any developed business unit ( form – report - process - menue , ... etc) by having templates with subclassing you can adjust the code of specified triggers ( subclassed one ) of 1000 form module for example in 1 menutes after compiling the 1000 if you use object classing , or only one minute without compiling if you call the code stored in pll library ,
also templates are very critical issue in the development process or the interface changing .
6- Commenting the code should include the name of author
, the date of creation, the date of adjustment, the reason,
simple description of the functionality of the code. ,and hints on every line important to know
7- Testing Procedures must be set , starting with the unit test , transaction test to improve the quality of the product the process can be as the following :
- Test the business unit against (insert , update, delete, and query functions)
- Test the business unit against the required validation of the form or the report
- Test the functionality of the form or report against the functionality in the whole system cycle.
- Maintain more than one test scenario for the business unit .
8- Performance considerations must be taken to improve the quality of the product according to your frame work and your requirements , forexample
- Any SQL statement must be written on the database side not in the forms side to avoide the network traffic caused by the database roundtrips
- Any business unit must be developed from the designed template ( Form module from the from module template , report from the report template, parameter form from the parameter form template ,….. etc) to centeralize the performance tunning issues
- Packages Should be maintained and used in the Development process to get their benefits in performance and organizing the work
- Naming Conventions of the forms , reports ,PLL libraries , OLB libraries , Object groups , Program units , canvases, blocks, …. Etc must be maintained to easily develop and maintain (easy and fast )
- Any common Pl/sql code must be packaged in the PLL libraries to ensure that the right code is used for the issue arised
- Any common interface items packaging should be packaged in Object group (for example approval process , contact object group )
- Primary keys must be numbers only and auto filled not user filled other unique columns like code can have unique constraint and can maintained by the user
- No composite primary keys are allowed
- Use the appropriate way to get block non related data ( Join – view – database function ) according to the situation rather than using the post – query trigger
- Any in ordinary way of coding must be discussed between team member before using it in the development process ( discussion among the team member is very important and very usefull process )
- Any object group, templates, Should be documented and has its read me file to guide the developer how to use it in the development process.
- The basic triggers of the form or the report mustn’t be used by the developer ( instead write the code in the called procedures in the original triggers for example design your when-new-form-instance to call the following procedure - p_before_init ;
Fram_work_code;
p_after_init ;
p_before_init ; is module program unit that the user can write his code when he want to execute his own code in the when new form instance trigger , and so on .....
- Messaging to the end user must be done through defined package in the system to facilitate any future modification or enhancements ( like multilingual messaging)
- Any interface item ( text item , display item , list item , Button , ….. etc) must be sub classed from the appropriate object ( smart class shoul be maintained to easily do this process)
- Any tabular Block should have indicator item to improve the interface looking and current record visual attribute
- Any huge number of columns to be displayed on the form should be set its canvas to stack canvas style to expand horizontally.
9- “ Know How “ documentation must be maintained to facilitate the work process and exchange the experience between team members
10- The implementation of the work to the production Environment must have documented procedures and flow chart ( this is very important issue )
11- Documentation of how to develop Form Module, how to develop Report module, how to develop parameter form Must be read before any development starts for the first time , to avoid the violation of develompment standrds
Read Client machine Information ( Get benefit of using the java beans in Forms)

Using java beans in your forms is very usefull action to increase your application performance , functionality , and interface attraction .
fore example
1- a java bean that restrict the input of text item to number will decrease network traffic if the user enter character.
2- a java bean that customize the shape of forms buttons will make your interface more attractive
3- a java bean that read client machine information , increase your forms functinality
in this post we will explain a java bean that can read client machine information ( webutil can do this also ) and pass it to the form
- consider that you want to know which Ip address currenty use this form
first step is to make the deployment steps of using java bean
1- pur the jar file in your java path
2- edit Archive_jinit parameter in your formsweb.cfg in your section to add this jar name
3- create a bean area in your forms
4- set the implementation class property of your bean item to
oracle.forms.fd.ClientInfos ( case sensitive)
5- write your code to get the information you want as follow :
- to get the Ip address and pass it to bind variable
:your bind variable:= Get_Custom_Property('your bean item', 1, 'IP' ) ;
- to get the operating system
:your bind variable : =get_custom_property('your bean item',1,'operating');
- to get the operating system user name
:your bind variable : =get_custome_property('your bean item',1,'username');
very important note :
-- if you want to get this information in "when new form instance "
you have to write your code in " when timer expired " to ensure that the form interface included the bean area is built
you can download the jar file from http://sheikyerbouti.developpez.com/forms-pjc-bean/menu/
Tuesday, August 11, 2009
PRAGMA autonmous_transaction
in the declaration section of your pl/sql code
pragma autonmous_transaction instruct oracle server to do the dml operations and commit or rollback independently of the calling environment
sample code :
create or replace procedure xx as
pragma autonmous_Transaction ;
begin
......
end;
Avoid Post - query code round trip (Block on join - Function based column sourc)
consider a asituation that you want to display the the dept name in your employees block , the old fashion and not efficient way is to write a select statemnt in Post-query trigger of your block using the value of the emp.deptid bind variable in your form , this way in this situation is not effecient as it make round tirp to the database to get the dept name , also you can suppose that the business requirement arisen to not display the deptname only , it needs to display 'deptname-deptlocation' , in this situation you will change all modules that display this field !!!!!!!
the most effecient way to display the dept name is to make a database function that have argument deptid and return the deptname ,
after that you can create a field in your emp block and change its property database to yes and its column source name to "your function name " , this will erase any roundtrip to the database in your post query trigger , also you can change the output of the function according any new business requirement , also you will write the code once and use it many times
--- block on join
suppose that you want to display 9 or more columns from the dept table with your emp table ( block on join will be the effecient way )
implementation of the block on join
- create your emp block
- create your other columns you need
- change the column source name of the emp block to 'emp,dept'
- change the source column property for your added column to the corresponding database column name ( don't forget prefex with table name)
- change the property of your emp blcok primary key to primary key - yes
- change the property query only , update allowed , insert allowed to yes, no , no respectively of your added columns
- change the properry " dml target name " of your block to 'emp'
run your form to show the result
Monday, August 10, 2009
Sending Email With Attachment
PROCEDURE ATTACH_BASE64
(P_CONN IN OUT NOCOPY UTL_SMTP.connection
,P_DATA IN BLOB
,P_MIME_TYPE IN VARCHAR2 := 'application/octet'
,P_INLINE IN BOOLEAN := TRUE
,P_FILENAME IN VARCHAR2 := NULL
,P_LAST IN BOOLEAN := FALSE
)
IS
i PLS_INTEGER;
len PLS_INTEGER;
BEGIN
attach_demo_mail.BEGIN_ATTACHMENT(p_conn, p_mime_type, p_inline, p_filename, 'base64');
-- Split the Base64-encoded attachment into multiple lines
i := 1;
len := DBMS_LOB.getLength(p_data);
WHILE (i < len) LOOP
IF(i + MAX_BASE64_LINE_WIDTH < len)THEN
UTL_SMTP.Write_Raw_Data (p_conn
, UTL_ENCODE.Base64_Encode(
DBMS_LOB.Substr(p_data, MAX_BASE64_LINE_WIDTH, i)
)
);
ELSE
UTL_SMTP.Write_Raw_Data (p_conn
, UTL_ENCODE.Base64_Encode(
DBMS_LOB.Substr(p_data, (len - i), i)
)
);
END IF;
UTL_SMTP.Write_Data(p_conn, UTL_TCP.CRLF);
i := i + MAX_BASE64_LINE_WIDTH;
END LOOP;
END_ATTACHMENT(p_conn, p_last);
END;
------------------------------------------------------------------------
After that you can make your private pkg the use the supplied package to sned your email with different type of attachment ( you can customize the code below according to your requirement)
Pre - requisities -- create your own table to load the blob files to it
CREATE TABLE GN_BLOB
(
BLOB_RECID NUMBER,
TEMP_FILE BLOB
)
CREATE OR REPLACE PACKAGE TMS.mail_Attach_pkg AS
/******************************************************************************
NAME: mail_Attach_pkg
PURPOSE:
REVISIONS:
Ver Date Author Description
--------- ---------- --------------- ------------------------------------
1.0 10/08/2009 1. Created this package.
******************************************************************************/
procedure p_load_file_to_db(p_file_name varchar2,p_recid out number);
PROCEDURE p_MAIL_WITH_ATTACHMENT(p_attach_type number,p_file_name varchar2,p_sender varchar2,p_receipients varchar2 ,p_subject varchar2,p_message varchar2);
END mail_Attach_pkg;
/
CREATE OR REPLACE PACKAGE BODY TMS.mail_attach_pkg AS
/******************************************************************************
NAME: mail_attach_pkg
PURPOSE:
REVISIONS:
Ver Date Author Description
--------- ---------- --------------- ------------------------------------
1.0 10/08/2009 1. Created this package body.
******************************************************************************/
procedure p_load_file_to_db(p_file_name varchar2,p_recid out number)is
LOBD BLOB;
FILS BFILE;
AMT INT;
v_Recid number(16);
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
-- get the record id for the blob
select seq_GN_blob.nextval into v_Recid from dual;
-- load html file to database
INSERT INTO GN_blob(temp_file,blob_recid) -- this your table that you will save the blob file to use it after that
VALUES(EMPTY_BLOB(),v_Recid)
RETURNING Temp_FILE INTO LOBD;
FILS:=BFILENAME('TEST_DIR', p_file_name);
DBMS_LOB.FILEOPEN(FILS, DBMS_LOB.FILE_READONLY);
AMT:= DBMS_LOB.GETLENGTH(FILS);
DBMS_LOB.LOADFROMFILE(LOBD, FILS, AMT); -- LOAD THE FILE directy to the data base
DBMS_LOB.FILECLOSE(FILS);
COMMIT;
p_Recid:=v_recid ;
end ;
--****************************************************************************************************************
PROCEDURE p_MAIL_WITH_ATTACHMENT(p_attach_type number ,p_file_name varchar2,p_sender varchar2,p_receipients varchar2 ,p_subject varchar2,p_message varchar2) is
t_conn UTL_SMTP.Connection;
t_blob BLOB;
-- cCRLF ; --VarChar2(2) := CHR(13) CHR(10);
v_Recid number(16);
BEGIN
--- load the file to the database
P_LOAD_FILE_TO_DB(p_file_name,v_recid);
-- load BLOB
DBMS_LOB.CREATETEMPORARY(t_blob, FALSE);
SELECT gn_blob.TEMP_FILE INTO t_blob FROM GN_blob WHERE blob_recid = v_recid;
-- start mail
t_conn := Attach_DEMO_MAIL.Begin_Mail(p_sender,
p_receipients,
p_subject,
attach_DEMO_MAIL.MULTIPART_MIME_TYPE);
-- some inline html text first line
attach_DEMO_MAIL.Attach_Text(t_conn, 'Dear sirs 'UTL_TCP.CRLF
' Good Day kindly find our attached report haythem mousa 'UTL_TCP.CRLF, 'text/plain');
--- second line
---attach_DEMO_MAIL.Attach_Text(t_conn, 'second line 'UTL_TCP.CRLF
---- ' 22222t 'UTL_TCP.CRLF, 'text/plain');
-- attachment
-- 'application/pdf' for PDF files
-- DEMO_MAIL.Attach_Base64(t_conn, t_blob, 'application/x-zip-compressed', TRUE, 'file.zip');
if p_attach_type=1 then
Attach_DEMO_MAIL.Attach_Base64(t_conn, t_blob, 'text/txt', TRUE, 'test.txt');
elsif p_attach_type=2 then
Attach_DEMO_MAIL.Attach_Base64(t_conn, t_blob, 'image/jpg', TRUE, 'sample.jpg');
elsif p_attach_type=3 then
Attach_DEMO_MAIL.Attach_Base64(t_conn, t_blob, 'application/pdf', TRUE, 'sample.pdf');
end if ;
-- some html attachment
---html attachment
--c_DEMO_MAIL.Attach_Text(t_conn, 'This is a HTML report.'
--cCRLF' good morning ', 'text/plain', FALSE,null);
-- end connection
attach_DEMO_MAIL.End_Mail(t_conn);
--DBMS_LOB.FREETEMPORARY(t_blob);
COMMIT;
END;
END mail_attach_pkg;
/
you can customize the code above to add,edit, delete features
Tuesday, August 4, 2009
KEY Flexfield generation on your application

- you can enhance the code provided and change it according to your environment of development ( as the code contains some specified piece of codes that related to my own development standards and environment )
at first we will explain the bussiness functionality and desgin of this process,
-the first step is to define value sets and value set details table to store the data about value set you want to use
- after that you can define the key flex field and define its detail information ( number of segment , prompt of each segment , sequqnece of each segment , .....) and assign a value set to each segment in the key flex field detail
- next step is to define a table to store the data combination of the different flex fields
here are sample scripts for these tabl creation ( note that the naming convention and some columns related to current environment)
-----------------------------------------
CREATE TABLE GN_VALUE_SET
(
VALUE_SET_RECID NUMBER NOT NULL,
VALUE_SET_NAME VARCHAR2(50 BYTE) NOT NULL,
VALUE_SET_DESC VARCHAR2(50 BYTE) NOT NULL,
SYSTEM_DATA NUMBER(2) DEFAULT 0,
CODE_LEN NUMBER(2) DEFAULT 3
)
TABLESPACE SYSTEM
PCTUSED 40
PCTFREE 10
INITRANS 1
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
FREELISTS 1
FREELIST GROUPS 1
BUFFER_POOL DEFAULT
)
LOGGING
NOCOMPRESS
NOCACHE
NOPARALLEL
MONITORING;
CREATE TABLE GN_VALUE_SET_DTL
(
VALUE_SET_DTL_RECID NUMBER NOT NULL,
VALUE_SET_RECID NUMBER,
VALUE_SET_CODE VARCHAR2(10 BYTE) NOT NULL,
VALUE_STATUS NUMBER(2) DEFAULT 1,
VALUE_SET_DESC VARCHAR2(50 BYTE),
VALUE_SET_EDESC VARCHAR2(50 BYTE)
)
TABLESPACE SYSTEM
PCTUSED 40
PCTFREE 10
INITRANS 1
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
FREELISTS 1
FREELIST GROUPS 1
BUFFER_POOL DEFAULT
)
LOGGING
NOCOMPRESS
NOCACHE
NOPARALLEL
MONITORING;
CREATE TABLE GN_FLEXFIELD_DET
(
FLEXFIELD_DET_RECID NUMBER(16),
FLEXFIELD_RECID NUMBER(16) NOT NULL,
SEGMENT_SERIAL NUMBER(2),
VALUE_SET_RECID NUMBER(16),
SEGMENT_ARABIC_PROMPT VARCHAR2(50 BYTE),
SEGMENT_ENGLISH_PROMPT VARCHAR2(50 BYTE),
SEGMENT_LEN NUMBER(5)
)
TABLESPACE USERS
PCTUSED 0
PCTFREE 10
INITRANS 1
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
BUFFER_POOL DEFAULT
)
LOGGING
NOCOMPRESS
NOCACHE
NOPARALLEL
MONITORING;
CREATE TABLE GN_FLEXFIELD_COMB
(
FLEXFIELD_COMB_RECID NUMBER(16),
FLEXFIELD_RECID NUMBER(16),
SEGMENT_COMB_VALUE VARCHAR2(200 BYTE),
SEGMENT_COMB_DESC VARCHAR2(500 BYTE)
)
TABLESPACE USERS
PCTUSED 0
PCTFREE 10
INITRANS 1
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
BUFFER_POOL DEFAULT
)
LOGGING
NOCOMPRESS
NOCACHE
NOPARALLEL
MONITORING;
CREATE TABLE GN_FLEXFIELD
(
FLEXFIELD_RECID NUMBER(16),
FLEXFIELD_NAME VARCHAR2(50 BYTE),
SEPARATOR VARCHAR2(1 BYTE),
SEGMENT_NUMBER NUMBER(2),
ALLOW_DYNAMIC_INSERT NUMBER(1) DEFAULT 1 NOT NULL,
ARABIC_WINDOW_PROMPT VARCHAR2(50 BYTE),
ENGLISH_WINDOW_PROMPT VARCHAR2(50 BYTE)
)
TABLESPACE USERS
PCTUSED 0
PCTFREE 10
INITRANS 1
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
BUFFER_POOL DEFAULT
)
LOGGING
NOCOMPRESS
NOCACHE
NOPARALLEL
MONITORING;
CREATE UNIQUE INDEX GN_FLEXFIELD_PK ON GN_FLEXFIELD
(FLEXFIELD_RECID)
LOGGING
TABLESPACE USERS
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
BUFFER_POOL DEFAULT
)
NOPARALLEL;
CREATE UNIQUE INDEX GN_FLEXFIELD_COMB_PK ON GN_FLEXFIELD_COMB
(FLEXFIELD_COMB_RECID)
LOGGING
TABLESPACE USERS
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
BUFFER_POOL DEFAULT
)
NOPARALLEL;
CREATE UNIQUE INDEX GN_FLEXFIELD_DET_PK ON GN_FLEXFIELD_DET
(FLEXFIELD_DET_RECID)
LOGGING
TABLESPACE USERS
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
BUFFER_POOL DEFAULT
)
NOPARALLEL;
CREATE UNIQUE INDEX PK_GN_VALUE_SET ON GN_VALUE_SET
(VALUE_SET_RECID)
LOGGING
TABLESPACE SYSTEM
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
FREELISTS 1
FREELIST GROUPS 1
BUFFER_POOL DEFAULT
)
NOPARALLEL;
CREATE UNIQUE INDEX PK_GN_VALUE_SET_DTL ON GN_VALUE_SET_DTL
(VALUE_SET_DTL_RECID)
LOGGING
TABLESPACE SYSTEM
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
FREELISTS 1
FREELIST GROUPS 1
BUFFER_POOL DEFAULT
)
NOPARALLEL;
CREATE OR REPLACE TRIGGER TRG_GN_VALUE_SET BEFORE INSERT ON GN_VALUE_SET REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE V_RECID NUMBER ;
BEGIN
SELECT SEQ_GN_VALUE_SET.NEXTVAL INTO V_RECID FROM DUAL ;
:NEW.VALUE_SET_RECID := V_RECID ;
END TRG_GN_VALUE_SET;
/
SHOW ERRORS;
CREATE OR REPLACE TRIGGER TRG_GN_VALUE_SET_DTL BEFORE INSERT ON GN_VALUE_SET_DTL REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE V_RECID NUMBER ;
BEGIN
SELECT SEQ_GN_VALUE_SET_DTL.NEXTVAL INTO V_RECID FROM DUAL ;
:NEW.VALUE_SET_DTL_RECID := V_RECID ;
END TRG_GN_VALUE_SET_DTL;
/
SHOW ERRORS;
CREATE OR REPLACE TRIGGER TRG_GN_FLEXFIELD_DET BEFORE INSERT ON GN_FLEXFIELD_DET REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE V_RECID NUMBER ;
BEGIN
SELECT SEQ_GN_FLEXFIELD_DET.NEXTVAL INTO V_RECID FROM DUAL ;
:NEW.FLEXFIELD_DET_RECID := V_RECID ;
END TRG_GN_FLEXFIELD_DET;
/
SHOW ERRORS;
CREATE OR REPLACE TRIGGER TRG_GN_FLEXFIELD_COMB BEFORE INSERT ON GN_FLEXFIELD_COMB REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE V_RECID NUMBER ;
BEGIN
SELECT SEQ_GN_FLEXFIELD_COMB.NEXTVAL INTO V_RECID FROM DUAL ;
:NEW.FLEXFIELD_COMB_RECID := V_RECID ;
END TRG_GN_FLEXFIELD_COMB;
/
SHOW ERRORS;
CREATE OR REPLACE TRIGGER TRG_GN_FLEXFIELD BEFORE INSERT ON GN_FLEXFIELD REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE V_RECID NUMBER ;
BEGIN
SELECT SEQ_GN_FLEXFIELD.NEXTVAL INTO V_RECID FROM DUAL ;
:NEW.FLEXFIELD_RECID := V_RECID ;
END TRG_GN_FLEXFIELD;
/
SHOW ERRORS;
ALTER TABLE GN_VALUE_SET ADD (
CONSTRAINT PK_GN_VALUE_SET
PRIMARY KEY
(VALUE_SET_RECID)
USING INDEX
TABLESPACE SYSTEM
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
FREELISTS 1
FREELIST GROUPS 1
));
ALTER TABLE GN_VALUE_SET_DTL ADD (
CONSTRAINT PK_GN_VALUE_SET_DTL
PRIMARY KEY
(VALUE_SET_DTL_RECID)
USING INDEX
TABLESPACE SYSTEM
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
FREELISTS 1
FREELIST GROUPS 1
));
ALTER TABLE GN_FLEXFIELD_DET ADD (
CONSTRAINT GN_FLEXFIELD_DET_PK
PRIMARY KEY
(FLEXFIELD_DET_RECID)
USING INDEX
TABLESPACE USERS
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
));
ALTER TABLE GN_FLEXFIELD_COMB ADD (
CONSTRAINT GN_FLEXFIELD_COMB_PK
PRIMARY KEY
(FLEXFIELD_COMB_RECID)
USING INDEX
TABLESPACE USERS
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
));
ALTER TABLE GN_FLEXFIELD ADD (
CONSTRAINT GN_FLEXFIELD_PK
PRIMARY KEY
(FLEXFIELD_RECID)
USING INDEX
TABLESPACE USERS
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE (
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS 2147483645
PCTINCREASE 0
));
ALTER TABLE GN_VALUE_SET_DTL ADD (
CONSTRAINT FK_GN_VALUE_REFERENCE_GN_VALUE
FOREIGN KEY (VALUE_SET_RECID)
REFERENCES GN_VALUE_SET (VALUE_SET_RECID));
-----------------------------------------------------
- Next step is to make your forms moudules that define value set and key flexfield and make the required functions and procedure to get information about value set or key flexfield it sefl
- after that you can make your object group that will contains the items , blocks, canvases,.... that will be used to implement this functionality
the object group should contain the following :
1- stack canvas 2- window 3- control block 4- two list of values one of them is dummy lov to be attached to the item in your form that will invoke the key flex field
5-one parameter with number data type to hold the value of the value set that will displayed for the current segment
6- pl/sql package that will contain all procedures and functions that will be implement that funcationality
7- the items in the block ( segment_1 , .... segment_6 ) this segments that will be displayed to the user according to the number of the segments defined in the choosed flexfield , i.e. if the flex field has 4 segments so the items ( segment_1,segment_2,....,segment_4) will be displayed to the user the same rule applied for the display items ( desc_1, ...,desc_6)
but the items value_set_1 ,..... value_set_6 will not displayed they are only for holding the value set record id that attach to corresponding segment , these items can be deleted and package variables used instead )
8- two display item to hold the selected value and describtion selected form the list of value from each segment
9- two display item to hold the combined value and combined desc , ( these two items can be replaced and package variables can be used )
here the code of the forms package included
-------------------------------------------------------------------
PACKAGE init_flexfield IS
flex_item_name_desc varchar2(200); -- to hold the item name that will hold the description of the combined value
flex_block_name varchar2(100);--- the block of the item that invoked the flex field
flex_recid number(16); -- the applied felx field --- hard coded ----
flex_window_prompt varchar2(50); --- hold the window prompt
flex_separator varchar2(1); ---flex_separator
flex_segment_number number(2); ---flex_segment_numbe
flex_dynamic_status boolean ; -- if the flex field allow to insert the non existed combination into the combination table
procedure invoke_flex_field(target_item varchar2, target_item_desc varchar2);
procedure invoke_lov ;
Procedure validate_segment_value;
procedure ensure_right_lov ;
Procedure combine_segments ;
procedure validate_combination ;
END;
----------------------------------------------------------------
----------------------------------------------------------------
:combined_value:='';
:combined_desc:='';
for i in 1..init_flexfield.flex_segment_number loop
:combined_value:=:combined_valueinit_flexfield.flex_separatorname_in('segment_'i);
:combined_desc:=:combined_descinit_flexfield.flex_separatorname_in('desc_'i);
end loop;
--- omit extra separator
:combined_value:=substr(:combined_value,2);
:combined_desc:=substr(:combined_desc,2);
---------------------------------------------------------------
procedure ensure_right_lov is
v_segment_number number(2);
begin
---- parameter init_valu_set that is used in calling the list of values accross all segments
v_cursor_segment:=:system.trigger_item;
v_segment_number:=to_number(substr(v_cursor_segment,-1));
:parameter.INIT_VALUE_SET:=name_in('value_set_'v_segment_number);
end ;
--------------------------------------------------------------------------
Procedure validate_segment_value is
v_cursor_segment varchar2(50);
v_segment_number number(2);
v_valid number(2);
v_segment_desc varchar2(50);
begin
INIT_FLEXFIELD.ensure_right_lov ;
v_cursor_segment:=:system.trigger_item;
v_segment_number:=to_number(substr(v_cursor_segment,-1));
v_valid:=flexfield_pkg.validate_sement_value(name_in(v_cursor_segment),name_in('value_set_'v_segment_number)) ;
if v_valid = 0 then
message('Invalid Value for the segment');
message('Invalid Value for the segment');
raise form_trigger_failure;
else
--- get the right desc for semgnet
v_segment_desc:=value_set_pkg.get_value_set_desc(:parameter.INIT_VALUE_SET,
value_set_pkg.get_detail_Recid(name_in('value_set_'v_segment_number),name_in('segment_'v_segment_number)
),translation_pkg.get_user_lang_id);
copy(v_segment_desc,'desc_'v_segment_number);
end if ;
end;
v_segment_number number(2);
begin
v_cursor_segment:=:system.trigger_item;
v_segment_number:=to_number(substr(v_cursor_segment,-1));
if show_lov('LOV_VALUE') then
--copy(:lov_desc,'desc_'v_segment_number);
else
message('you must choose value from list');message('');
raise form_trigger_failure ;
end if ;
end ;
---------------------------------------------------------------------------------------------------------------
order by segment_serial ;
v_counter number(16);
begin
---- initialize package variables
init_flexfield.flex_item_name:=target_item;
init_flexfield.flex_item_name_desc:=target_item_desc ;
init_flexfield.flex_recid:=flexfield_pkg.get_account_flexfield(1);
init_flexfield.flex_window_prompt:=flexfield_pkg.get_flexfield_window_prompt(init_flexfield.flex_recid,translation_pkg.get_user_lang_id);
init_flexfield.flex_separator:=flexfield_pkg.get_flexfield_separator(init_flexfield.flex_recid);
init_flexfield.flex_segment_number:=flexfield_pkg.get_flexfield_segment_number(init_flexfield.flex_recid);
init_flexfield.flex_dynamic_status:=flexfield_pkg.get_dynamic_insert_flag(init_flexfield.flex_recid) ;
init_flexfield.flex_block_name:=:system.trigger_block;
set_canvas_property('flex_can',width,(init_flexfield.flex_segment_number*100)+24);
set_window_property('flex_window',width,(init_flexfield.flex_segment_number*100)+24);
--- center the button
set_item_property('flex_block.flex_ok',x_pos,((((init_flexfield.flex_segment_number*100)+24)-100)/2));
set_item_property('flex_block.flex_cancel',x_pos,((((init_flexfield.flex_segment_number*100)+24)-100)/2)+60);
set_item_property('segment_'i,visible,property_true);
set_item_property('segment_'i,enabled,property_true);
set_item_property('segment_'i,navigable,property_true);
set_item_property('desc_'i,visible,property_true);
end loop;
:combined_desc:='';
---- set prompt of the segment -- and assign the value set of each segment to the corresponding item
for rec in c_cur loop
copy('','segment_'v_counter);
copy('','desc_'v_counter);
copy(rec.value_set_recid,'value_set_'v_counter);
v_segment_prompt:=flexfield_pkg.get_segment_prompt(rec.flexfield_det_recid,translation_pkg.get_user_lang_id);
set_item_property('segment_'v_counter,prompt_text,v_segment_prompt);
v_counter:=v_counter+1;
end loop;
-- show the flex field cnavas and window
go_block('FLEX_BLOCK');
SET_FORM_PROPERTY(GET_APPLICATION_PROPERTY (CURRENT_FORM_NAME),VALIDATION_UNIT,ITEM_SCOPE);
end ; --- invoke flex field
init_flexfield.combine_Segments;
if flexfield_pkg.check_combination_exist(init_flexfield.flex_recid,:combined_value)=0 then --- the combination not existed before
--- check if the current flexfiedl allow dynamic insertion of non existed combination
if init_flexfield.flex_dynamic_status =true then
--- insert the combination
flexfield_pkg.generate_combination(init_flexfield.flex_recid,:combined_value,:combined_desc);
else
message ('This combination not existed ');message ('This combination not existed ');
raise form_trigger_failure ;
end if ;
end if;
copy(:combined_value,init_flexfield.flex_item_name);
copy(:combined_DESC,init_flexfield.flex_item_name_desc);
go_block(init_flexfield.flex_block_name);
go_item(init_flexfield.flex_item_name);
end ;
--#########################################################################3
END;
---------------------------- Some Data base packages Used ---------------------
CREATE OR REPLACE PACKAGE BODY TMS.flexfield_pkg AS
/******************************************************************************
NAME: flexfield_pkg
PURPOSE:
REVISIONS:
Ver Date Author Description
--------- ---------- --------------- ------------------------------------
1.0 28/07/2009 1. Created this package body.
******************************************************************************/
Function get_dynamic_insert_flag(p_flexfield_recid number) return boolean is
v_result number(2);
cursor c_cur is (select gn_flexfield.ALLOW_DYNAMIC_INSERT from gn_flexfield where gn_flexfield.FLEXFIELD_RECID = p_flexfield_recid) ;
begin
open c_cur ;
fetch c_cur into v_result;
if c_cur%notfound then
close c_cur ;
return false ;
end if ;
close c_cur ;
if v_result =1 then
return true;
elsif v_result =0 then
return false ;
else
return false ;
end if ;
end;
--**********************************************************************************************
Function check_combination_exist(p_flexfield_recid number , p_combination varchar2) return number is
cursor c_cur is (select gn_flexfield_comb.FLEXFIELD_COMB_RECID from gn_flexfield_comb where gn_flexfield_comb.FLEXFIELD_RECID=p_flexfield_Recid
and gn_flexfield_comb.SEGMENT_COMB_VALUE= p_combination);
v_return number(16);
begin
if p_flexfield_Recid is null or p_combination is null then
return null;
end if ;
open c_cur ;
fetch c_cur into v_Return;
if c_cur%notfound then
v_return:=0;
end if ;
close c_cur ;
if v_return>0 then
v_return:=1;
end if ;
return v_return ;
end ;
--****************************************************************************************
Procedure generate_combination(p_flexfield_recid number , p_combination varchar2,p_combination_desc varchar2) is
PRAGMA AUTONOMOUS_TRANSACTION;
begin
insert into gn_flexfield_comb (gn_flexfield_comb.FLEXFIELD_RECID,gn_flexfield_comb.SEGMENT_COMB_VALUE,gn_flexfield_comb.SEGMENT_COMB_DESC)
values (p_flexfield_recid,p_combination,p_combination_desc);
commit;
end ;
----*********************************************************************************************
function validate_sement_value(p_seg_value varchar2, p_value_set_Recid number) return number is
cursor c_cur is (select count(*) from gn_value_set_dtL where (gn_value_set_dtl.VALUE_SET_CODE =p_seg_value and
gn_value_set_dtl.VALUE_SET_RECID=p_value_set_Recid) AND gn_value_set_dtL.VALUE_STATUS=1 );
v_return number(16);
begin
open c_cur ;
fetch c_cur into v_return ;
close c_cur ;
return v_return;
end ;
--*******************************************************************************************
Function get_account_flexfield(p_sob_recid number) return number is
begin
return 1;
end ;
--******************************************************************************/
function get_segment_value_set_Recid ( p_segment_recid number) return number is
cursor c_cur is (select gn_flexfield_det.VALUE_SET_RECID from gn_flexfield_det where gn_flexfield_det.flexfield_det_Recid= p_segment_recid );
v_return number(16);
begin
if p_segment_recid is null then
return null;
end if ;
open c_cur ;
fetch c_cur into v_Return ;
if c_cur%notfound then
close c_Cur ;
return null;
end if ;
close c_cur ;
return v_return;
end ;
---******************************************************************************************
function get_segment_prompt(p_segment_recid number,v_lang_recid number) return varchar2 is
cursor c_cur is (select gn_flexfield_det.SEGMENT_ARABIC_PROMPT from gn_flexfield_det where gn_flexfield_det.flexfield_det_Recid= p_segment_recid);
cursor c_cur_e is (select gn_flexfield_det.segment_english_prompt from gn_flexfield_det where gn_flexfield_det.flexfield_det_Recid= p_segment_recid );
v_return varchar2(50);
begin
if p_segment_recid is null or v_lang_recid is null then
return null;
end if ;
if v_lang_recid =1 then
open c_cur ;
fetch c_cur into v_Return ;
if c_cur%notfound then
close c_Cur ;
return null;
end if ;
close c_cur ;
else
open c_cur_e ;
fetch c_cur_e into v_Return ;
if c_cur_e%notfound then
close c_Cur_e ;
return null;
end if ;
close c_cur_e;
end if ;
return v_return;
end ;
---**************************************************************************************************
Function get_flexfield_segment_number(p_flexfield_Recid number) return number is
cursor c_cur is (select gn_flexfield.SEGMENT_NUMBER from gn_flexfield where gn_flexfield.flexfield_Recid= p_flexfield_recid);
v_return number(2);
begin
if p_flexfield_recid is null then
return null;
end if ;
open c_cur ;
fetch c_cur into v_Return ;
if c_cur%notfound then
close c_Cur ;
return null;
end if ;
close c_cur ;
return v_return;
end ;
---*********************************************************************************
Function get_flexfield_separator(p_flexfield_recid number)return varchar2 is
cursor c_cur is (select gn_flexfield.SEPARATOR from gn_flexfield where gn_flexfield.flexfield_Recid= p_flexfield_recid);
v_return varchar2(1);
begin
if p_flexfield_recid is null then
return null;
end if ;
open c_cur ;
fetch c_cur into v_Return ;
if c_cur%notfound then
close c_Cur ;
return null;
end if ;
close c_cur ;
return v_return;
end ;
---************************************************************************************************
Function get_flexfield_window_prompt(p_flexfield_recid number,v_lang_id number ) return varchar2 is
cursor c_cur is (select gn_flexfield.arabic_window_prompt from gn_flexfield where gn_flexfield.flexfield_Recid= p_flexfield_recid);
cursor c_cur_e is (select gn_flexfield.english_window_prompt from gn_flexfield where gn_flexfield.flexfield_Recid= p_flexfield_recid );
v_return varchar2(50);
begin
if p_flexfield_recid is null then
return null;
end if ;
if v_lang_id =1 then
open c_cur ;
fetch c_cur into v_Return ;
if c_cur%notfound then
close c_Cur ;
return null;
end if ;
close c_cur ;
else
open c_cur_e ;
fetch c_cur_e into v_Return ;
if c_cur_e%notfound then
close c_Cur_e ;
return null;
end if ;
close c_cur_e;
end if ;
return v_return;
end ;
--################################################################################3
END flexfield_pkg;
/
---------------------------------------------------------------------------------
the code in the segments item triggers
1- key list value init_flexfield.invoke_lov;
2- pre-text init_flexfield.ensure_right_lov ;
3-When - validate item init_flexfield.validate_segment_value ;
the code that you will write it to invoke the flexfield from your form
init_flexfield.invoke_flex_field('TARGET_ITEM','target_item_desc');
Sunday, August 2, 2009
DML Error Log Feature
-- first step is to make the database know which table you want to log by running the followin procedure
dbms.errorlog.create_error_log('your table name','error_log_yourtablename');
- a table will be created fo you with some built in columns and the coluns of your table
-- the second step is to add the procedure that run the error loggin process into your DML plsql code
-- LOG ERRORS INTO ERROR_LOG_TABLENAME REJECT LIMIT 1;
-- you can use this clause in the merge statement like this
merge into (table)
using (table,view)
on (condition)
when matched then
(update st)
when not matchec then ()
[log errors into .......... reject limit 1]