Thanks Scott.
It was a stupid typo and is working just fine now.
Rich
________________________________
On 5/9/2022 12:13 PM, Scott Klement wrote:
Hi Rich,
On 5/9/2022 10:32 AM, Rich Loeber wrote:
Yep .... when it is a really odd problem, it is usually something stupid like that.
Rich
DCL VAR(&APIERR) TYPE(*CHAR) LEN(50)
DCL VAR(&APIK14) TYPE(*CHAR) LEN(10) VALUE('*SEC')
CALL PGM(QRCVDTAQ) PARM(&DQNAME &QLIBR &FLDLEN +
&FIELD &SECONDS &APIK6 &APIK7 &APIK8 +
&APIK9 &APIK10 &APIOPT &APILEN *APIERR +
&APIK14)
If you pass *APIERR, this will pass the character string '*APIERR' in the error code parameter to the API, which is not not legitimate. The API is expecting the first 4 bytes of the parameter to be an integer containing the length of the parameter.
Since your &APIERR variable is 50 bytes long, the first 4 bytes of the 50 should contain the value x'00000032' (hex 32 = decimal 50). But you are passing '*API' as the first 4 bytes, which in hex is x'5CC1D7C9', or in decimal 1,556,207,561. So it thinks you are telling it that you've provided a variable that is 1.5 GB long.
The API error code is meant to be a data structure containing these fields:
- bytes 1-4 = binary length of the parameter
- bytes 5-8 = binary length of the data the API has placed into the structure (returned to you)
- bytes 9-15 = the message id (most commonly CPFxxxx)
- byte 16 = reserved
- bytes 17-END = any variable data ("MSGDTA") that goes in the message.
So with 50 bytes, bytes 17-50 (length 34) would be available for variable data.
It's important to understand that this is one parameter (not multiple) and contains all of this data as part of the parameter. i.e. a data structure in most languages.
You can check the 2nd field (bytes 5-8) to determine if an error occurred. Set it to 0 before calling the API, and if it's not 0 afterwards, you know there was an error. You can also determine the length of the returned message data by subtracting 16 from it, so if that second field was 26, it means 10 bytes of message data was returned.
Here's an example of defining the API error in CL.
PGM
DCL VAR(&APIERR) TYPE(*CHAR) LEN(50)
DCL VAR(&LENPROV) TYPE(*INT) LEN(4) +
STG(*DEFINED) DEFVAR(&APIERR 1)
DCL VAR(&LENAVAIL) TYPE(*INT) LEN(4) +
STG(*DEFINED) DEFVAR(&APIERR 5)
DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) +
STG(*DEFINED) DEFVAR(&APIERR 9)
DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(34) +
STG(*DEFINED) DEFVAR(&APIERR 17)
CHGVAR VAR(&LENPROV) VALUE(50)
CHGVAR VAR(&LENAVAIL) VALUE(0)
/* CALL QRCVDTAQ HERE, PASS &APIERR AS 13TH PARAMETER */
IF (&LENAVAIL *NE 0) DO
/* AN ERROR OCCURRED. THE MESSAGE ID IS IN &MSGID */
ENDDO
ENDPGM
This is using the "defined on" syntax to create one 50 byte field with sub-fields containing the values within in... the CL version of a data structure.
You may also run into older examples that use %BIN and %SST to access the subfields instead of using the "defined on" syntax (which is less code and, in my opinion, easier to read.)
PGM
DCL VAR(&APIERR) TYPE(*CHAR) LEN(50)
CHGVAR VAR(%BIN(&APIERR 1 4)) VALUE(50)
CHGVAR VAR(%BIN(&APIERR 5 4)) VALUE(0)
/* CALL QRCVDTAQ HERE, PASS &APIERR AS 13TH PARAMETER */
IF (%BIN(&APIERR 5 4) *NE 0) DO
/* AN ERROR OCCURRED. THE MESSAGE ID IS: */
CHGVAR VAR(&MSGID) VALUE(%SST(&APIERR 17 7))
ENDDO
ENDPGM
Hope that helps.
As an Amazon Associate we earn from qualifying purchases.