Passing Variable Length fields between RPG and CL |
RPG IV program or procedures supports the variable length fields(using the VARYING keyword), however ILE CL does not support the variable length fields and this creates an error Length of varying length variable is out of range (C G D F) when we do pass the field lets say length 10 in CL to the 10 length Varying field in RPGLE program/procedure.
For Example
There is one CL program that declares name character variable of length 10 and pass it as a parameter to RPG IV program using CALLPRC and in RPG IV program that NAME variable is defined as variable length character field using VARYING keyword in PR and PI. So this gives error Length of varying length variable is out of range. See the below CL and RPG script that will cause this error.
CL1 program
PGM DCL VAR(&NAME) TYPE(*CHAR) LEN(10) VALUE('AMIT') CALLPRC PRC(RPG1) PARM((&NAME *BYREF *DFT)) RETURN ENDPGM
command used to create CL1 module
CRTCLMOD MODULE(EASYCLASS1/CL1) SRCFILE(EASYCLASS1/JAN2024) SRCMBR(CL1) REPLACE(*YES) DBGVIEW(*SOURCE)
command used to create CL1 program
CRTPGM PGM(EASYCLASS1/CL1) MODULE(EASYCLASS1/CL1 RPG1) ACTGRP(*CALLER)
RPG1 program
DRPG1 PR D NAME 10A CONST VARYING DRPG1 PI D NAME 10A CONST VARYING Dl_NAME S 10A VARYING /free l_Name = NAME; return; /end-free
command used to create RPG1 module
CRTSQLRPGI OBJ(EASYCLASS1/RPG1) SRCFILE(EASYCLASS1/JAN2024) SRCMBR(RPG1) COMMIT(*NONE) OBJTYPE(*MODULE) REPLACE(*YES) DBGVIEW(*SOURCE)
command used to create RPG1 program
CRTPGM PGM(EASYCLASS1/RPG1) MODULE(EASYCLASS1/RPG1) ACTGRP(*CALLER)
Call program and Error occurred
CALL CL1
Display Program Messages Job 378884/EASYCLASS/QPAD185446 started on 01/29/24 at 19:32:21 in subsystem Length of varying length variable is out of range (C G D F). Type reply, press Enter. Reply . . . ___________________________________________________________ __________________________________________________________________________
Why this issue occurs
The problem here in the above example is that CL program does not support the variable length fields and RPGLE do support variable length fields. So, when we pass a fixed length character field like the &NAME variable in above example rom program CL1 i.e CLLE program to RPGLE program named RPG1 then that RPG1 program/procedure expects a variable field length, the field length attribute is not included and is missing and RPG1 program assumes that the data is corrupted.
Variable Length Fields
Variable length field basically consists of two parts:
- an integer field that holds the length(binary value): holds the current length of the field content
- followed by the actual data itself
For fields length upto 65535 characters, that integre portion is of two bytes in length and for fields longer than 65535 then that length portion occupies 4 bytes in length. Therefore, it is clear that variable length fields always occupies more bytes than its defined length.
If we consider above example program RPG1 and CL1, then For a varying field length of 10 occupies 12 bytes of storage. Those extra bytes are two byte binary value stored internally as a two byte binary prefix and the field length attribute is hidden by RPG IV because of RPG intergrated support for variable field length. The two byte prefix length is automatically inserted and maintained by the RPG compiler.
Finally, Passing Variable length fields from RPG to RPG/calling proceudre is easy as the compiler itself ensures that the data is formatted properly. However, when we call the RPG procedure from CL, no prototyping involved in that case and one has to manually ensure that the passed variable is properly formatted as per defined in RPG.
CL support for Variable length fields
CL does not have support for the variable field lengths. Therefore, in order to properly pass a variable field length from CL to PRG IV program/procedure we have to manually prefix the 2 byte length (binary) in the field and increasing the length as well. Therefore, if we consider above example, the &NAME field should be increased from length 10 to 12 in CL program and added two bytes to the field length. To achieve this we use %BIN CK built-in function.
Syntax of %BIN CL built-in function
%BIN CL built-in function accepts a field name, a starting position, and a length(number of characters)
%BIN(Character-Field-Name Start-Position Length)
Correctly passing variable length field between CL and RPG
CL2 program
PGM DCL VAR(&NAME) TYPE(*CHAR) LEN(12) CHGVAR VAR(%SST(&NAME 3 10)) VALUE('AMIT') CHGVAR VAR(%BIN(&NAME 1 2)) VALUE(4) CALLPRC PRC(RPG1) PARM((&NAME *BYREF *DFT)) RETURN ENDPGM
command used to create CL1 module
CRTCLMOD MODULE(EASYCLASS1/CL2) SRCFILE(EASYCLASS1/JAN2024) SRCMBR(CL2) REPLACE(*YES) DBGVIEW(*SOURCE)
command used to create CL1 program
CRTPGM PGM(EASYCLASS1/CL2) MODULE(EASYCLASS1/CL2 RPG1) ACTGRP(*CALLER)
RPG1 program
DRPG1 PR D NAME 10A CONST VARYING DRPG1 PI D NAME 10A CONST VARYING Dl_NAME S 10A VARYING /free l_Name = NAME; return; /end-free
command used to create RPG1 module
CRTSQLRPGI OBJ(EASYCLASS1/RPG1) SRCFILE(EASYCLASS1/JAN2024) SRCMBR(RPG1) COMMIT(*NONE) OBJTYPE(*MODULE) REPLACE(*YES) DBGVIEW(*SOURCE)
command used to create RPG1 program
CRTPGM PGM(EASYCLASS1/RPG1) MODULE(EASYCLASS1/RPG1) ACTGRP(*CALLER)
Call program and Success
CALL CL2
This time program will be run fine without any error.