We are facing a data exception error in a PL/1 program, when a non numeric value is being checked for zeros in an IF statement. We are facing this issue when the program is compiled in Enterprise PL/i and not in earlier compilers. It will be greatful, if someone can help me with how to resolve this issue and let us know how to check a variable's type in PLI so that we can check whether it is numeric or not before the IF Condition.
Joined: 14 Jan 2008 Posts: 2501 Location: Atlanta, Georgia, USA
Below is an Assembler sub-program which can be called from PL/I to validate decimal-data. It uses the "TEST PACK" instruction, which is a somewhat fairly new instruction. However, you need to contact your System's folks and verify that you have "THE EXTENDED-TRANSLATION FACILITY 2" installed. Example syntax (from COBOL) is given in the source, so you'll just have to access it via the proper PL/I syntax.
Code:
***********************************************************************
*---------------------------------------------------------------------*
* *
* THE EXTENDED-TRANSLATION FACILITY 2 MUST BE INSTALLED IN *
* ORDER FOR THE 'TP' (TEST PACK) INSTRUCTION TO WORK. *
* *
* EXAMPLE 'CALL' FROM COBOL: *
* *
* 03 WS-PARM-LGTH PIC 9(04) BINARY. *
* 03 WS-PARM-DATA PIC X(16). *
* 03 WS-TESTPKD PIC X(08) VALUE 'TESTPKD'. *
* 03 WS-DECIMAL-X PIC X(05). *
* *
* MOVE X'123456789C' TO WS-DECIMAL-X. *
* MOVE WS-DECIMAL-X TO WS-PARM-DATA. *
* MOVE LENGTH OF WS-DECIMAL-X TO WS-PARM-LGTH. *
* *
* CALL WS-TESTPKD USING WS-PARM-LGTH, *
* WS-PARM-DATA. *
* *
* UPON RETURN, THE 'RETURN-CODE' SPECIAL-REGISTER (R15) WILL *
* EQUAL ZERO (VALID PACKED-DECIMAL DATA), 08 (INVALID DATA) OR *
* 16 (INVALID DATA LENGTH). *
* *
* AFTER ISSUING THE OBLIGATORY 'BCTR,0', AN 'SLL,4' IS ISSUED *
* AGAINST R7. THIS IS NECESSARY FOR THE 'EX' TO 'OR' THE *
* ADJUSTED-LGTH INTO BITS 8-15 OF THE 'TP' INSTRUCTION. *
* *
* SO FOR EXAMPLE, IF THE ADJUSTED R7 = X'00000005', IT WILL *
* CONTAIN X'00000050' AFTER THE SHIFT. *
* *
*---------------------------------------------------------------------*
***********************************************************************
TESTPKD CSECT
USING *,R3 INFORM ASSEMBLER
SAVE (14,12) SAVE REGISTERS
LA R3,0(,R15) R3 IS BASE-REGISTER
L R7,0(,R1) POINT TO HWORD-LGTH
LH R7,0(,R7) LOAD AS HWORD
LA R15,16 SET RETURN-CODE
CHI R7,1 ZERO OR NEGATIVE LGTH?
BL RTN2CLLR YES, RETURN TO CALLER
CHI R7,16 EXCEEDS MAXIMUM-LGTH?
BH RTN2CLLR YES, RETURN TO CALLER
BCTR R7,0 REDUCE BY ONE
SLL R7,4 SHIFT-LEFT 4-BITS FOR 'EX'
L R9,4(,R1) POINT TO DATA-PARM
LA R9,0(,R9) CLEAR TOP-BIT
LA R15,8 SET RETURN-CODE
EX R7,VALIDATE VALID DECIMAL-DATA?
BNZ RTN2CLLR NO, RETURN TO CALLER
SLR R15,R15 ALL IS WELL
RTN2CLLR EQU *
*
RETURN (14,12),RC=(15) RETURN TO THE CALLER
*
VALIDATE TP 0(00,R9) EXECUTED 'TP' (LGTH IN R7)
*
LTORG , LITERAL-ORG
*
TESTPKD AMODE 31
TESTPKD RMODE ANY
*
YREGS REGISTER-EQUATE MACRO
*
END , END 'TESTPKD'
Joined: 13 Jan 2022 Posts: 5 Location: South Africa
Functions / algorithms using Verify to check for a valid numeric field (DEC / PIC / CHAR from CICS screen containing a PIC or DEC) can be dicey (e.g. if a text amount field contains two decimal points your verify test will pass it).
The best way to properly verify that a field is valid, is to let PL/1 do it for you!
This way, the answer you get from the test is 100% aligned with what will happen when you use that field.
I have variations on this function for PIC fields, CHAR fields (supposedly containing integer numbers or amounts with decimals) etc. , but you will see the principle is the same:
Code:
/********************************************************************/
/* A M O U N T V A L I D */
/* */
/* TEST CHAR(14) FIELD FROM SCREEN FOR BEING A VALID DECIMAL(13,2) */
/********************************************************************/
AMOUNT_VALID: PROC(AMOUNT) RETURNS(BIT);
DCL AMOUNT CHAR(14);
PROCESS:
DO;
DCL VALID BIT INIT ('1'B);
DCL TEMP_AMOUNT FIXED DECIMAL(13,2) INIT(0);
IF AMOUNT = '' THEN LEAVE PROCESS;
ON CONVERSION BEGIN;
VALID = '0'B;
GOTO CONT1;
END;
TEMP_AMOUNT = AMOUNT;
CONT1: REVERT CONVERSION;
END PROCESS;
RETURN(VALID);
END AMOUNT_VALID;
What happens here is that you are using PL/1's ON ERROR functionality to trap the specific kind of error you are worried about (which is an exact prediction of whether you will get e.g. ONCODE 612 "for real"). Then you revert (switch off that error trapping again), so that whatever error trapping was in effect before this call, is reset to exactly what it was before this call.
In effect:
Set specific error handling trap locally
Do the actual operation you fear may cause a data exception (but in an isolated test case in my function example)
See if the real error handler trapped it, or let it pass
set your "validate" function's return value
revert the error handling back to whatever was in effect.
You could do this in line where you actually use the field and hit the exception , but I prefer an isolated self contained function, so that the main code remains easily readable & focused.
The error handler is quite interesting. It has "scope" just like variables, and it stacks.