How to handle Forms 6 in LoadRunner

How to handle Forms 6 in LoadRunner

1) Record application using latest patch for LR using full trace and recording log.

2) Identify stored procedures used by Forms 6.  In the recording log you can identify them by calls to Forms6_UPI_function.  In the .c files you can identify them because you will see a call to lrd_stmt with a comment starting with “/* select text from sys.all_source where “.  These lines will also include the text “/* INSERT PARAMETERS HERE */”.

You need to identify the owner of the stored procedure, the name of the package in which it occurs, and the name of the procedure itself.

In the recorded script I see there are two stored procedures.  For one of them

lrd_stmt(Csr20, “/* select text from sys.all_source where owner = ‘CIDDEV’ ”

“and name = ‘SEARCH_ENGINE’; */  BEGIN SEARCH_ENGINE.SEARCH_QUERY(/* ”

“INSERT PARAMETERS HERE */); END;”, -1, 0 /*Non deferred*/,

1 /*Dflt Ora Ver*/, 0);

was recorded.  For the other

lrd_stmt(Csr20, “/* select text from sys.all_source where owner = ‘CIDDEV’ ”

“and name = ‘CID_GEN_PCK’; */  BEGIN CID_GEN_PCK.GET_SD_DESCR(/* ”

“INSERT PARAMETERS HERE */); END;”, -1, 0 /*Non deferred*/,

1 /*Dflt Ora Ver*/, 0);

was recorded.

The owner can be identified by the string appearing after “owner =”.

The package name can be identified by the string appearing after “name =”.

The procedure name can be identified by the string appearing after the package name and the “.” afterwards.

First stored procedure:

owner = ‘CIDDEV’

package name = ‘SEARCH_ENGINE’

procedure name = ‘SEARCH_QUERY’

Second stored procedure:

owner = ‘CIDDEV’

package name = ‘CID_GEN_PCK’

procedure name = ‘GET_SD_DESCR’

3) Determine the names and types of all the arguments to the stored procedures that appeared in the generated script.  If they are functions that return a value, what is the type of the return value?  For the other arguments, determine whether they are input-only, output-only, or both input and output.

The type can be a scalar type, such as NUMBER or VARCHAR2, or a compound type such as RECORD of other types or a TABLE of another type.

For Oracle 8.x, you can determine this information for all the procedures in a package by using SQL*Plus and performing DESCRIBE on the owner and package name in SQL*Plus.  You perform DESCRIBE on the owner name, “.”, and the package name.

Example:

SQL> DESCRIBE CIDDEV.SEARCH_ENGINE;

FUNCTION TABLE_RECORD RETURNS TABLE OF RECORD

Argument Name                  Type                    In/Out Default?

—————————— ———————– —— ——–

P1                             TABLE OF RECORD         IN

POUT1                    TABLE OF RECORD         IN/OUT

P2                             VARCHAR2                       OUT

In this example, the function SEARCH_ENGINE.TABLE_RECORD in the CIDDEV schema returns a result that is a TABLE OF RECORD.  It takes 3 arguments, P1, POUT1, and P2.  P1 is an input-only parameter which is a TABLE OF RECORD.  P2 is an input/output parameter of the same type.  P2 is an output parameter of type VARCHAR2.  It is not known from here what type of record is used in the TABLE OF RECORD for P1, POUT1, and the result type of the function.

This information can be obtained by querying the ALL_ARGUMENTS table.  Choose the correct procedure by examining the OWNER, PACKAGE_NAME, and OBJECT_NAME fields.  Show the ARGUMENT_NAME, DATA_TYPE, and IN_OUT fields.  Sort the arguments by POSITION.  Show only top-level arguments by making sure DATA_LEVEL = 0.

Example:

SELECT ARGUMENT_NAME, DATA_TYPE, IN_OUT

FROM ALL_ARGUMENTS

WHERE OWNER = ‘ORAFORMS’ AND PACKAGE_NAME = ‘TABLE_OF_RECORDS’ AND OBJECT_NAME = ‘TABLE_RECORD’ AND DATA_LEVEL = 0

ORDER BY POSITION;

ARGUMENT_NAME                  DATA_TYPE                      IN_OUT

—————————— ——————————           ———

PL/SQL TABLE                    OUT

P1                                           PL/SQL TABLE                    IN

POUT1                                  PL/SQL TABLE                    IN/OUT

P2                                           VARCHAR2                          OUT

This is similar to output produced by describing the stored procedure in SQL*Plus.

SQL> DESCRIBE ORAFORMS.TABLE_OF_RECORDS;

FUNCTION TABLE_RECORD RETURNS TABLE OF RECORD

Argument Name                  Type                                                 In/Out Default?

—————————— ———————–                      —— ——–

P1                                          TABLE OF RECORD           IN

POUT1                                 TABLE OF RECORD           IN/OUT

P2                                          VARCHAR2                          OUT

If the DATA_TYPE is a compound type, like a PL/SQL TABLE or PL/SQL RECORD, it is necessary to determine how the data type is composed of simpler types.  Querying the POSITION, SEQUENCE, DATA_LEVEL, TYPE_OWNER, TYPE_NAME, TYPE_SUBNAME fields in order to obtain this information.

SELECT DATA_LEVEL, POSITION, ARGUMENT_NAME, DATA_TYPE, TYPE_OWNER, TYPE_NAME, TYPE_SUBNAME

FROM ALL_ARGUMENTS

WHERE OWNER = ‘ORAFORMS’ AND PACKAGE_NAME = ‘TABLE_OF_RECORDS’ AND OBJECT_NAME = ‘TABLE_RECORD’

ORDER BY SEQUENCE;

Start of output:

DATA_LEVEL   POSITION ARGUMENT_N DATA_TYPE       TYPE_OWNER TYPE_NAME

———- ———- ———- ————— ———- ———-

TYPE_SUBNA

———-

0          0 [NULL]     PL/SQL TABLE    ORAFORMS   OBJECT

AEXRECTYPE

1          1 [NULL]     PL/SQL RECORD   ORAFORMS   OBJECT

EXRECTYPE

2          1 ID         NUMBER          [NULL]     [NULL]

[NULL]

DATA_LEVEL   POSITION ARGUMENT_N DATA_TYPE       TYPE_OWNER TYPE_NAME

———- ———- ———- ————— ———- ———-

TYPE_SUBNA

———-

2          2 NAME       VARCHAR2        [NULL]     [NULL]

[NULL]

0          1 P1         PL/SQL TABLE    ORAFORMS   OBJECT

AEXRECTYPE

The result type of the function appears first.  It is of type ORAFORMS.OBJECT.AEXRECTYPE, which is a PL/SQL TABLE.  The next row shows that this is a TABLE of EXRECTYPE.  This row also shows that EXRECTYPE is a PL/SQL RECORD.  Note that the DATA_LEVEL of this row is 1, which shows that it is a further description of the information at DATA_LEVEL 0. The next two rows appear at DATA_LEVEL 2, and show that EXECRECTYPE is a RECORD with two fields.  One is ID, which is a NUMBER.  The other is NAME, which is a VARCHAR2.  The following row has DATA_LEVEL 0, which shows that it is a new parameter to the stored procedure.  It is the P1 parameter, which is also of type AEXRECTYPE.

If one of the fields of a RECORD is a string type (VARCHAR2, CHAR, etc.), you can find the size of the field by looking at the DATA_LENGTH column in ALL_ARGUMENTS.

Cautions

a) Oracle allows overloading stored procedures so that more than one stored procedure has the same package name and procedure name as long as the argument types differ.  We are assuming here that the correct instance function can be chosen if a function name can be overloaded.  You can check if a procedure name is overloaded by examining the OVERLOAD field of ALL_ARGUMENTS.  This field will be NULL if the name is not overloaded.  If it is overloaded, then it will be 1 for the first overloaded instance, 2 for the second instance, etc.

SELECT DISTINCT OWNER, PACKAGE_NAME, OBJECT_NAME, OVERLOAD

FROM ALL_ARGUMENTS

WHERE OWNER = ‘CIDDEV’ AND PACKAGE_NAME = ‘SEARCH_ENGINE’ AND OBJECT_NAME = ‘TABLE_RECORD’;

b) Not all Oracle stored procedures are part of a package.  In that case the PACKAGE_NAME is NULL and the OBJECT_NAME gives the name of the procedure in the ALL_ARGUMENTS table.

4) It is necessary to determine the value of the arguments passed to the stored procedure as input and to print out the arguments from the stored procedure after the call so we can correlate queries if necessary.

We can do this by modifying the text of the stored procedure to print out these values.  We only need to do this during recording.  Before trying to replay the script, we will need to restore the stored procedure to its original text.

a)      Find text of stored procedure

You can obtain the text of the body of a package by querying the ALL_SOURCE table for its TEXT field.  Specify the package name by restricting the OWNER and NAME fields.  You can sort the text by its line number, though it appears that it normally is presented in sorted order.

Example:

SELECT TEXT

FROM ALL_SOURCE

WHERE OWNER = ‘QATEST’ AND NAME = ‘MY_MATH’ AND TYPE = ‘PACKAGE BODY’

ORDER BY LINE;

Rows of result:

PROCEDURE MY_SQUARE(X IN NUMBER, Y OUT NUMBER) IS

END MY_MATH;

BEGIN

Y := X * X;

END MY_SQUARE;

END MY_MATH;

You can look at the package declaration instead of the package body by searching for the ‘PACKAGE’ type instead of the ‘PACKAGE BODY’ type.

You can reconstruct the package in SQL*Plus by adding the line

CREATE OR REPLACE

before the text of the package that was returned by this query and adding a line containing

/

after this text.  This is useful because it is necessary to modify the stored procedure in order to record the values of the parameters passed to and from the stored procedure.

Make sure the text of the stored procedure is not truncated if there is a long row.  You might have to redefine the formatting used if a row is truncated.  The following statement in SQL*Plus causes 1000 characters to be printed for each line of TEXT.  This probably is more than enough to avoid truncation.

COLUMN TEXT FORMAT A1000

b)      Modify stored procedure to print arguments

(i) Simple case – procedure with scalar arguments (NUMBER, CHAR, DATE, etc.)

I assume that there is a procedure called TEMP_DUMP that takes a string argument, and somehow writes this argument to disk.  I’ll describe one way of implementing TEMP_DUMP later.

Add calls to TEMP_DUMP at the beginning and end of the stored procedure in order to see the values used by the stored procedure.  Each IN or IN/OUT parameter should be printed at the beginning of the stored procedure.  Each OUT or IN/OUT parameter should be printed at the end of the stored procedure.

For the sample package above, you could add trace statements to get:

CREATE OR REPLACE

PACKAGE BODY MY_MATH IS

PROCEDURE MY_SQUARE(X IN NUMBER, Y OUT NUMBER) IS

BEGIN

TEMP_DUMP(‘BEGIN MY_SQUARE PRELOG’);

TEMP_DUMP(‘X = ‘ || X);

TEMP_DUMP(‘END MY_SQUARE PRELOG’);

Y := X * X;

TEMP_DUMP(‘BEGIN MY_SQUARE POSTLOG’);

TEMP_DUMP(‘Y = ‘ || Y);

TEMP_DUMP(‘END MY_SQUARE POSTLOG’);

END MY_SQUARE;

END MY_MATH;

When MY_MATH.MY_SQUARE(5, :X) was performed this yielded the log

BEGIN MY_SQUARE PRELOG

X = 5

END MY_SQUARE PRELOG

BEGIN MY_SQUARE POSTLOG

Y = 25

END MY_SQUARE POSTLOG

(ii) function

If a function is used instead of a procedure, make sure the function stores the return value in a variable, and print the value of this variable before returning the result.  Treat this variable similar to the way you would treat an OUT parameter.

PACKAGE BODY MY_MATH IS

FUNCTION MY_SQUARE(X IN NUMBER) RETURN NUMBER IS

RETVAL NUMBER;

BEGIN

TEMP_DUMP(‘BEGIN MY_SQUARE PRELOG’);

TEMP_DUMP(‘X = ‘ || X);

TEMP_DUMP(‘END MY_SQUARE PRELOG’);

RETVAL := X * X;

TEMP_DUMP(‘BEGIN MY_SQUARE POSTLOG’);

TEMP_DUMP(‘RETVAL = ‘ || RETVAL);

TEMP_DUMP(‘END MY_SQUARE POSTLOG’);

RETURN (RETVAL);

END MY_SQUARE;

END MY_MATH;

(iii) BOOLEAN type

If a variable is of type BOOLEAN then print its value in a separate IF statement.

IF XBOOL THEN TEMP_DUMP(‘XBOOL  =  TRUE’);

ELSE TEMP_DUMP(‘XBOOL  =  FALSE’);

END IF;

(iv) RECORD type

If the type is a record type, then print out the value of each of the fields of the record.

Example:

PACKAGE MY_MATH IS

TYPE NUMREC IS RECORD (A NUMBER, B NUMBER);

PROCEDURE MY_ADD(X IN OUT NUMREC);

END MY_MATH;

PACKAGE BODY MY_MATH IS

PROCEDURE MY_ADD(X IN OUT NUMREC) IS

BEGIN

TEMP_DUMP(‘BEGIN MY_DOUBLE PRELOG’);

TEMP_DUMP(‘X.A = ‘ || X.A);

TEMP_DUMP(‘X.B = ‘ || X.B);

TEMP_DUMP(‘END MY_DOUBLE PRELOG’);

X.A := X.A + X.B;

TEMP_DUMP(‘BEGIN MY_DOUBLE POSTLOG’);

TEMP_DUMP(‘X.A = ‘ || X.A);

TEMP_DUMP(‘X.B = ‘ || X.B);

TEMP_DUMP(‘END MY_DOUBLE POSTLOG’);

END MY_ADD;

END MY_MATH;

(v) TABLE type

If a TABLE type is used, then it is necessary to print values for each row of the table.

Example:

PACKAGE MY_MATH IS

TYPE NUMTAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;

PROCEDURE MY_DOUBLE(X IN OUT NUMTAB);

END MY_MATH;

PACKAGE BODY MY_MATH IS

PROCEDURE MY_DOUBLE(X IN OUT NUMTAB) IS

J BINARY_INTEGER;

BEGIN

TEMP_DUMP(‘BEGIN MY_DOUBLE PRELOG’);

TEMP_DUMP(‘X.FIRST = ‘ || X.FIRST);

TEMP_DUMP(‘X.LAST = ‘ || X.LAST);

FOR J IN X.FIRST .. X.LAST LOOP

TEMP_DUMP(‘X[‘ || J || ‘]=’ || X(J));

END LOOP;

TEMP_DUMP(‘END MY_DOUBLE PRELOG’);

FOR J IN X.FIRST .. X.LAST LOOP

X(J) := X(J) * 2;

END LOOP;

TEMP_DUMP(‘BEGIN MY_DOUBLE POSTLOG’);

TEMP_DUMP(‘X.FIRST = ‘ || X.FIRST);

TEMP_DUMP(‘X.LAST = ‘ || X.LAST);

FOR J IN X.FIRST .. X.LAST LOOP

TEMP_DUMP(‘X[‘ || J || ‘]=’ || X(J));

END LOOP;

TEMP_DUMP(‘END MY_DOUBLE POSTLOG’);

END MY_DOUBLE;

END MY_MATH;

This procedure doubles the values of all elements of a table.  Here is a sample log created for executing this procedure:

BEGIN MY_DOUBLE PRELOG

X.FIRST = 1

X.LAST = 2

X[1]=66

X[2]=55

END MY_DOUBLE PRELOG

BEGIN MY_DOUBLE POSTLOG

X.FIRST = 1

X.LAST = 2

X[1]=132

X[2]=110

END MY_DOUBLE POSTLOG

(vi) If the type is a combination of compound types, such as a TABLE OF RECORD, print out all fields and all rows.  For example create a FOR loop over the rows of the table, and print out every field for each row.

c)       An implementation of dump procedure

There are probably many ways of implementing a dump procedure to print out the values used by the stored procedures.  The following definitions show one way of doing this, though they cause a COMMIT to be performed each time information is logged.  Caution:  this can cause problems if a transaction needs to be rolled back or another transaction is not yet ready to read the changes made by the transaction.

CREATE TABLE TEMP_LOG(ID NUMBER, TEXT VARCHAR2(100));

CREATE SEQUENCE TEMP_SEQUENCE;

CREATE OR REPLACE

PROCEDURE TEMP_DUMP(msg CHAR) IS

BEGIN

INSERT INTO TEMP_LOG values(TEMP_SEQUENCE.nextval, msg);

COMMIT;

END;

To show the log, perform

SELECT TEXT FROM TEMP_LOG ORDER BY ID;

5) Generating code for stored procedure

a)      Determining the statement to be executed

(i) Simple case – procedure with scalar arguments (NUMBER, CHAR, DATE, etc.)

If the stored procedure only takes scalar arguments, then the statement to be executed has a simple form.  The statement is of the form “BEGIN schema.package.procedure(arg1, arg2, …); END;”  For example for the first version of MY_SQUARE presented above the statement would be

BEGIN ORAFORMS.MY_MATH.MY_SQUARE(:X_01, :Y_02); END;

The schema name “ORAFORMS” can be omitted if it is the current schema.

(ii) function

For a function it is necessary to define an auxiliary variable RET_VALUE to store the return value.  This variable is otherwise treated like an output parameter.

For the function version of MY_SQUARE we would get

DECLARE RETVALUE_01 NUMBER;

BEGIN RETVALUE_01 := ORAFORMS.MY_MATH.MY_SQUARE(:X_02); END;

(iii) BOOLEAN type

If a stored procedure takes an argument of type BOOLEAN, pass a value of type INTEGER to the statement.  Declare a local variable of type BOOLEAN.  If the integer value is 0, then use FALSE for the BOOLEAN, else use true.

DECLARE XBOOL_01;

BEGIN

IF :XINT_01 = 0 THEN XBOOL_01 := FALSE;

ELSE XBOOL_01 := TRUE;

END IF;

schema.package.procedure(XBOOL_01);

END;

(iv) RECORD type

If a RECORD type is used for input or output, use separate placeholders for each field of the record.  Use a temporary variable for the record itself.  Copy from the placeholder to the temporary variable for IN parameters.  Copy back to the placeholder for OUT parameters.

DECLARE X NUMREC;

BEGIN

X_00.A := :A_01; X_00.B := :B_02;

MY_MATH.MY_ADD(X_00.A, X_00.B);

:A_01 := X_00.A; :B_02 := X_00.B;

END;

PACKAGE MY_MATH IS

TYPE NUMREC IS RECORD (A NUMBER, B NUMBER);

PROCEDURE MY_ADD(X IN OUT NUMREC);

END MY_MATH;

(v) TABLE type

If a TABLE type is used for an input or output parameter, and the TABLE is a TABLE of ordinary scalar values, then it is not necessary to write anything special for the statement.  Just pass the TABLE as a parameter to the stored procedure.

BEGIN MY_MATH.MY_DOUBLE(:X_01); END;

(vi) TABLE OF RECORD type

If a TABLE OF RECORD is used, then it is represent each field of the TABLE as an array.  Add a temporary variable I of type BINARY_INTEGER to be a loop index. Add a temporary variable to represent the TABLE OF RECORD.  For IN parameters, copy the value of the fields into the TABLE OF RECORD.  Call the stored procedure.  For OUT parameters, copy back the values from the TABLE OF RECORD to the individual fields.

The copying between the TABLE OF RECORD and the individual fields must be in a loop, since it is necessary to copy every single row of the TABLE.  For IN parameters, look at the number of rows passed to the stored procedure during recording, and hard code that into the statement.  For OUT parameters, use the FIRST and LAST functions to determine the size of the TABLE after the call.

Example from TABLE_OF_RECORDS.TABLE_RECORD in section 3).

DECLARE I binary_integer;

P1_01 ORAFORMS.object.aExRecType; POUT1_02 ORAFORMS.object.aExRecType;

RETVALUE_00 ORAFORMS.object.aExRecType;

BEGIN

FOR I IN 1..2 LOOP P1_01(I).ID := :ID_01(I); P1_01(I).NAME := :NAME_02(I); END LOOP;

FOR I IN 1..0 LOOP POUT1_02(I).ID := :ID_03(I); POUT1_02(I).NAME := :NAME_04(I);

END LOOP;

RETVALUE_00 := TABLE_OF_RECORDS.TABLE_RECORD(P1_01, POUT1_02, :P2_05);

FOR I IN POUT1_02.FIRST .. POUT1_02.LAST LOOP

:ID_11(I) := POUT1_03(I).ID; :NAME_12(I) := POUT1_04(I).NAME;

END LOOP;

FOR I IN  RETVALUE_00.FIRST .. RETVALUE_00.LAST LOOP

:ID_06(I) := RETVALUE_00(I).ID;

:NAME_07(I) := RETVALUE_00(I).NAME;

END LOOP;

END;

The TABLE_RECORD function takes three arguments:  P1 an IN parameter of type AEXRECTYPE, POUT1 an IN/OUT parameter of type AEXRECTYPE, and P2 an OUT parameter of type VARCHAR2.  The function returns a value of type AEXRECTYPE.

On input the P1 parameter contained 2 rows, while the POUT parameter contained 0 rows.  The LOOP for POUT for 1..0 can be omitted, since it will never be executed.  We don’t know how many rows will be returned after the procedure, so we loop from RETVALUE_00.FIRST to RETVALUE_00.LAST.

b)      Insert all of the lrd code necessary for replay

In addition to forming the Oracle statement to be executed, other lrd statements must be used.  We will illustrate what needs to be done for the last example, the call to TABLE_OF_RECORDS.TABLE_RECORD, since it shows how to handle a TABLE OF RECORD, one of the more difficult types to handle.

Remove the code that is currently inserted for the stored procedure.  This includes removing calls to lrd_open_cursor and lrd_stmt.

Insert the following in vdf.h.

// Define variable descriptors for P1 parameter.

// Since there are most 2 rows for this TABLE OF RECORD.the 2nd item in these two structure is 2.

// The field size for ID_01_D1 is 23, since VARNUM’s take up 23 bytes.

// The field size for NAME_02_D2 is 27, since there are 25 bytes for the NAME field of AEXRECTYPE plus 2 spare bytes.

static LRD_VAR_DESC                        ID_01_D1 =

{LRD_VAR_DESC_EYECAT, 2, 23, LRD_DBTYPE_ORACLE, {1, 0, 0}, DT_VARNUM};

static LRD_VAR_DESC                        NAME_02_D2 =

{LRD_VAR_DESC_EYECAT, 2, 27, LRD_DBTYPE_ORACLE, {1, 1, 0},

DT_SF_STRIPPED_SPACES};

// Variable descriptors for POUT1 parameter.  Similar to variable descriptors for P1 parameter.

static LRD_VAR_DESC                        ID_03_D3 =

{LRD_VAR_DESC_EYECAT, 2, 23, LRD_DBTYPE_ORACLE, {1, 0, 0}, DT_VARNUM};

static LRD_VAR_DESC                        NAME_04_D4 =

{LRD_VAR_DESC_EYECAT, 2, 27, LRD_DBTYPE_ORACLE, {1, 1, 0},

DT_SF_STRIPPED_SPACES};

// Variable descriptor for P2 scalar parameter.  Since it is a VARCHAR2 field, and string length is 10, since at most 9 characters are found in this string + one character for terminating null character.

// Second item in structure is 1, since this is a scalar.

static LRD_VAR_DESC                        P2_05_D5 =

{LRD_VAR_DESC_EYECAT, 1, 10, LRD_DBTYPE_ORACLE, {1, 1, 0},

DT_SF_STRIPPED_SPACES};

// Variable descriptors for return value fields.

static LRD_VAR_DESC                        ID_06_D6 =

{LRD_VAR_DESC_EYECAT, 2, 23, LRD_DBTYPE_ORACLE, {1, 0, 0}, DT_VARNUM};

static LRD_VAR_DESC                        NAME_07_D7 =

{LRD_VAR_DESC_EYECAT, 2, 25, LRD_DBTYPE_ORACLE, {1, 1, 0},

DT_SF_STRIPPED_SPACES};

// Declare statement handle for stored procedure call

static void FAR *           OraStm0;

// Declare bind handles for placeholders involving stored procedure call

static void FAR *           OraBnd01;

static void FAR *           OraBnd02;

static void FAR *           OraBnd03;

static void FAR *           OraBnd04;

static void FAR *           OraBnd05;

static void FAR *           OraBnd06;

static void FAR *           OraBnd07;

Insert the following in the .c file.

// General format

// lrd_ora8_handle_alloc to allocate statement handle

// lrd_ora8_stmt to prepare statement

// For each value assigned to a placeholder, use lr_assign

// For each placeholder, lr_ora8_bind_placeholder

// lrd_ora8_exec to execute statement containing stored procedure

// lrd_ora8_handle_free to free statement handle

// Environment handle OraEnv0 and service handle OraSvc0 must be defined previously.

// Use the current environment and service handles here instead of the names given below.

lrd_ora8_handle_alloc(OraEnv0, STMT, &OraStm0, 0);

lrd_ora8_stmt(OraStm0, /* statement from 5) a) (vi) above */, 1, 0, 0);

// Use an lrd_assign for each row of the field in an input array.  First ID field of P1 parameter.

lrd_assign(&ID_01_D1, “11”, 0, 0, 0);       // ID of 1st record is 11.  Could be seen from log of step 4).

lrd_assign(&ID_01_D1, “12”, 0, 1, 0);       // ID of 2nd record is 12.

// Use LRD_BIND_AS_ARRAY for type of lrd bind.

lrd_ora8_bind_placeholder(OraStm0, &OraBnd01, “ID_01”, &ID_01_D1, LRD_BIND_AS_ARRAY, 0);

// Do the same for NAME field of P1 parameter

lrd_assign(&NAME_02_D2, “Markn1”, 0, 0, 0);   // NAME of 1st record is “Markn1”

lrd_assign(&NAME_02_D2, “Markn2”, 0, 1, 0);   // NAME of 2nd record is “Markn2”

lrd_ora8_bind_placeholder(OraStm0, &OraBnd02, “NAME_02”, &NAME_02_D2, LRD_BIND_AS_ARRAY, 0);

// Binds for IN OUT parameter POUT2

// Since there were 0 rows for it on input, no lrd_assign’s are necessary

lrd_ora8_bind_placeholder(OraStm0, &OraBnd03, “ID_03”, &ID_03_D3, LRD_BIND_AS_ARRAY, 0,            0);

lrd_ora8_bind_placeholder(OraStm0, &OraBnd04, “NAME_04”, &NAME_04_D4, LRD_BIND_AS_ARRAY, 0, 0);

// P2 is a scalar parameter (NUMBER).  Use 0 as lrd bind type, not LRD_BIND_AS_ARRAY.

// If lrd_assign were called here, 2nd to last argument would be 0, since scalar type used.

// However, since P2 is an OUT parameter, no lrd_assign is needed.

lrd_ora8_bind_placeholder(OraStm0, &OraBnd05, “P2_05”, &P2_05_D5, 0, 0, 0);

// Binds for value returned by stored procedure.

lrd_ora8_bind_placeholder(OraStm0, &OraBnd06, “ID_06”, &ID_06_D6, LRD_BIND_AS_ARRAY, 0, 0);

lrd_ora8_bind_placeholder(OraStm0, &OraBnd07, “NAME_07”, &NAME_07_D7, LRD_BIND_AS_ARRAY, 0, 0);

lrd_ora8_exec(OraSvc0, OraStm0, 1, 0, &uliRowsProcessed, 0, 0, 0, 0, 0);

lrd_handle_free(&OraStm0, 0);

Advertisements

One thought on “How to handle Forms 6 in LoadRunner

  1. arunkumar

    Good and informative article, It would have been much better if it includes sample replay log for the script for better understanding.

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s