Fixed FormatFree Format
Coding in Free-Form RPG IV - a beginner's tutorial. The manuals for RPG in the Info Center; The coding examples are intended to show the feature being discussed. Modern ILE RPG now (finally) supports “fully-free” RPG Source code. No more jumping to character 10 to get passed the old reserved (H,F,D,I,C,O) specification column. You must code.FREE in column 1 of the first line of any source member that contains fully-free code.FREE cannot be coded anywhere but the first line. After that line, the entire source member must be free-format. You can also specify%KDS ( dataStruct: 3) and the compiler will use the first 3 (in this example) subfields of the specified data structure as the key fields. You can put any number you want in the 2nd parameter, again as long as it is less than or equal to the number of keyfields in the file.
Coding in Free-Form RPG IV - a beginner's tutorial. Short URL for this page. That you know where to find the manuals for RPG in the Info Center; The coding examples are intended to show the feature being discussed, but they sometimes have a 'Bonus features for this example' section following the example that will list additional interesting. In fixed format RPG IV, I used the TIME operation code to get the current date and time; but TIME is not supported by free format. You mentioned that the%DATE,%TIME, and%TIMESTAMP functions can replace TIME, but I’m not sure how to use them for this purpose. RPGLE free format Call program example - AS400 (iSeries) Free-format RPGLE does not support CALL. The only call possible in free-format is the prototype call, CALLP.
EVAL
Note:Some free format examples only work with V5R1 and higher.
Note:In free format the EVAL operation is not required sometimes.
Multiple Examples follow:
/FREE
EVALTotal = A * (B – 1)Total = A * (B – 1);
EVALTotal = Total +1Total = Total + 1;
Total += 1;//Short for previous example
EVALTotal = Total – CountTotal = Total – Count;
Total -= Count; //Short for previous example
EVALTotal = Total * CountTotal = Total * Count;
Total *= Count;//Short for previous example
EVALTotal = Total / 7Total = Total / 7;
Total /= 7;//Short for previous example
![Rpg Rpg](/uploads/1/2/4/8/124870837/118405976.gif)
Total = Total ** 2;//Exponentiation
Total **= 2;//Exponentiation
//Short for previous example
EVAL(H)Interest = Rate * AmtEVAL(H) Interest = Rate * Amt; //EVALused for half adjust
EVALA = %TRIMR(‘Hi ‘) +A = %TRIMR(‘Hi ‘) + %TRIML(Chars);
%TRIML(Chars)
***After the EVAL below, the value of Chars contains ‘ab****ghijklmno’
EVAL%SUBST(Chars:3:4) = ‘****’%SUBST(Chars:3:4) = ’****’;
/END-FREE
EVALR
Note:The expression is evaluation and the result is placed right-adjusted in the result field.
/FREE
EVALRName = ‘Jimmie‘EVALR Name = ‘Jimmie‘;
//Name =‘Jimmie‘//Name = ‘Jimmie‘
EVALRName = %TRIMR(‘Jimmie‘)EVALR Name = %TRIMR(‘Jimmie‘;
//Name = ‘Jimmie’//Name = ‘Jimmie’
/END-FREE
Fixed FormatFree Format
ELSEIF
Note:Instead of Nesting Ifs use an ELSEIF or a SELECT/ENDSL below.
In the last stage of the ELSEIF, the ‘ELSE’ part is optional.
/FREE
IFAge >= 20 and Sex = ‘F’IF Age >= 20 and Sex = ‘F’;
EVALCode = 5Code = 5;
ELSEIFAge >= 20 and Sex = ‘M’ELSEIF Age >= 20 and Sex = ‘M’;
EVALCode = 4Code = 4;
ELSEIFAge >= 30 and Sex = ‘F’ELSEIF Age >= 30 and Sex = ‘F’;
EVALCode = 10Code = 10;
ELSEIFAge >= 30 and Sex = ‘M’ELSEIF Age >= 30 and Sex = ‘M’;
EVALCode = 9Code = 9;
ELSEELSE
EVALCode = 20Code = 20;
ENDIFENDIF;
/END-FREE
SELECT/ENDSL
Note:Instead of Nesting Ifs use a SELECT/ENDSL or an ELSEIF above.
In the last stage of the SELECT, the ‘OTHER’ part is optional.
/FREE
SELECTSELECT;
WHENAge >= 20 and Sex = ‘F’WHEN Age >= 20 and Sex = ‘F’;
EVALCode = 5Code = 5;
WHENAge >= 20 and Sex = ‘M’WHEN Age >= 20 and Sex = ‘M’;
EVALCode = 4Code = 4;
WHENAge >= 30 and Sex = ‘F’WHEN Age >= 30 and Sex = ‘F’;
EVALCode = 10Code = 10;
WHENAge >= 20 and Sex = ‘M’WHEN Age >= 30 and Sex = ‘M’;
EVALCode = 9Code = 9;
OTHEROTHER;
EVALCode = 20Code = 20;
ENDSLENDSL;
/END-FREE
Fixed FormatFree Format
FOR
Note:Controls the number of times a group of operations are processed.
/FREE
EVALFactor = 1Factor = 1;
FORI =1 to %LEN(Field)FOR I = 1 to %LEN(Field);
EVALFactor = Factor + 1Factor = Factor + 1;
ENDFORENDFOR;
/END-FREE
%CHAR
Note:Converts the value of the expression from graphic, UCS-2, numeric, date, time,
or timestamp data to type character.
/FREE
EVALResult= ‘It is ‘ + %CHAR(Time)Result = ‘It is ‘ +%CHAR(Time)
+ ‘ on ‘ + %CHAR(Date)+ ‘ on ‘ + %CHAR(Date);
*** Result = ‘It is 12:23:34 on 02/02/1977’
/END-FREE
%EDITC
Note:Returns a character result representing the edited number after applying and edit code.
/FREE
EVALSal =‘The annual salary is ‘Sal = ‘The annual salary is ‘
+ TRIM(%EDITC(Amt * 12+ TRIM(%EDITC(Amt * 12
:’A’ : *CURSYM)):’A’: *CURSYM));
*** Sal = ‘The annual salary is $12,000.00’
/END-FREE
ADDDUR
Note:The ADDDUR operation adds the duration specified in factor 2 to a date or time and places the resulting Date, Time or Timestamp in the result field.
/FREE
BillDateADDDUR30:*DAYSDueDateDueDate = BillDate + %DAYS(30);
/END-FREE
SUBDUR
Note:Subtract a duration to establish a new Date, Time or Timestamp.
/FREE
DueDateSUBDUR30:*DAYS BillDateBillDate = DueDate - %DAYS(30);
/END-FREE
Fixed FormatFree Format
EXTRCT
Note:Extracts a portion of a date, time, or timestamp data item.
/FREE
EXTRCTBirthDate:*YBirthYearBirthYear = %SUBDT(BirthDate:*YEARS);
/END-FREE
%DEC / %DECH / %UNS / %UNSH / %INT / %INTH / %FLOAT
Note:As of V5R2 you can convert character arguments to numeric with all of these functions.
Note:These functions can now be used to support “LEGACY” code.
Note:The sign (+ or -), decimal point (. or ,),are optional.
Note:Invalid numeric data will set %STATUS = 00105.
/FREE
EVALChars = ‘-123.56’Chars = ‘-123.56’;
EVALNum = %DEC(Chars:5:2)Num = %DEC(Chars:5:2);//Num = -123.56
Rpg Free Sql Examples
EVALNum = %UNSH(Chars)Num = %UNSH(Chars);//Num = 124
/END-FREE
***D Spec:
D ToDateS80INZ(20021231)
D WorkDateSD
Fixed Format
EVALToDate = 20021231
EVALWorkDate = %DATE(ToDate:*ISO) //WorkDate = D’2002-12-31’
EVALWorkDate = WorkDate + %DAYS(30)//Add 30 days to WorkDate
EVALToDate = %UNS(%CHAR(WorkDate:*ISO))//ToDate = 20030130
Free Format
/FREE
ToDate = 20021231;
WorkDate = %DATE(ToDate:*ISO);//WorkDate = D’2002-12-31’
WorkDate = WorkDate + %DAYS(30);//Add 30 days to WorkDate
ToDate = %UNS(%CHAR(WorkDate:*ISO));//ToDate = 20030130
/END-FREE
Fixed FormatFree Format
%TIME / %TIMESTAMP
Note:Converts the value of the expression from character, numeric, or |timestamp data to type time. The converted value remains unchanged, but |is returned as a time.
Note:Available as of V5R2.
/FREE
EVALString = ’12:34 PM’String = ’12:34 PM’;
EVALTime = %TIME(String,*USA)Time = %TIME(String:*USA);
//Time = t’12.34.00’
/END-FREE
Fixed FormatFree Format
%DIFF
Note:Used to find the duration between:two dates, two times, two timestamps, a date and the date
portion of a timestamp, and a time and the time portion of a timestamp.
/FREE
EVALDaysLeft = %DIFF(ExamDate:DaysLeft = %DIFF(ExamDate:Today:*DAYS);
Today:*DAYS)/END-FREE
MONITOR/ENDMON
Note:May be used with V5R1 and later.
Note:Used for error handling routines.ON-ERROR list one or more errors for which it is responsible.
These errors generally correspond to the %STATUS code from 00100 to 09999 or you can use *FILE
for file errors.
/FREE
MONITORMONITOR;
READRickfileREAD Rickfile;
![Rpg Free Examples Rpg Free Examples](/uploads/1/2/4/8/124870837/167499979.jpg)
DOWNOT %EOF(Rickfile)DOW NOT %EOF(Rickfile);
KEYCHAINRickfile2CHAIN KEY Rickfile2;
EXSRDoSomethingEXSR DoSomething;
READRickfileREAD Rickfile;
ENDDOENDDO;
ON-ERROR1211ON-ERROR 1211;
EXSRNotOpenEXSR NotOpen;
ON-ERROR1218ON-ERROR 1218;
EXSRLockedRecEXSR LockedRec;
ON-ERROR*FILEON-ERROR *FILE;
EXSRFileErrEXSR FileErr;
ON-ERROR00100 : 00121ON-ERROR 00100 : 00121;
***Handle string error and array-index error***********************
EXSRSTRARYEXSR STRARY;
ON-ERRORON-ERROR;
***Handle all other errors**************************************
Rpg Free %lookup Examples
EXSRGenErrEXSR GenErr;
ENDMONENDMON;
/END-FREE
Fixed FormatFree Format
LEAVESR
Note:Used with free format only.Leaves a subroutine.
/FREE
LEAVESR;
/END-FREE
MOVE AND MOVEL
Note:RPGIV and free format provides a smoother process.
OLD RPGIII:
MOVELFIELD1FIELDA
MOVEFIELD2FIELDA
MOVELFIELDAFIELDB
MOVEFIELD3FIELDB
NEW RPGIV and free format:
/FREE
EVALFieldB = Field1 + Field2 + Field3FieldB = Field1 + Field2 + Field3;
/END-FREE
INDICATOR DATA TYPE
Note: Some free format examples only work with V5R1 and higher.
Note:Some languages refer to this as a Boolean data type.An indicator field is a single-byte field
that can contain only two logical values: ‘1’ or ‘0’.You can also refer to these values using *ON
and *OFF, respectfully.Indicator data is usually used within an RPGIV program to signal a true/false
condition and can be tested on as a true/false condition.
Examples follow:
D Spec:
DIsGoodSNINZ(*OFF)
/FREE
EXSRChkGoodEXSR ChkGood;
IFIsGoodIF IsGood;
EXSRDoSomethingEXSR DoSomthing;
EVALIsGood = *OFFIsGood = *OFF;
ELSEELSE;
EXSRGiveErrEXSR GiveErr;
ENDIFENDIF;
/END-FREE
Active3 years, 1 month ago
When working with embedded SQL in RPG, you often end up with a cursor and a
dow
-loop for processing all rows in your result. The condition in the loop is somehow dependent on SQLCOD
and/or SQLSTT
, some globally available variables in an SQLRPGLE-program?But what is the correct way of checking these values? Some suggest
SQLCOD = 0
others not (SQLCOD = +100 or SQLSTT = '02000')
. One fails on all warnings, the other does not fail on some errors, so I'm not content.To illustrate what I do with some code:
I'm looking for the correct return statement here, that will make me go through all rows if no error occurs and lets me leave when an error occurs. Bonus points for some decent way to check for errors.
kratenkokratenko5,51944 gold badges3030 silver badges5252 bronze badges
3 Answers
SQLSTATE is better, and recommended by IBM.
From IBM's InfoCenter SQL Messages and Codes Reference: SQLCODE and SQLSTATE concepts
SQLSTATE is the preferred standard return code.
SQLSTATE is 5 characters, with the first two bytes identifying a class of conditions.
- '00' = Unqualified Successful Completion
- '01' = Warning
- '02' = No Data
Anything else is an error. I generally only check for '00'.
Simple. Easy. More portable.
Using SQLCODE often involves lists of codes which are, IMHO, less than developer friendly.
Example:
Personally, I generally include definitions and code like this:
Then after any SQL operation, I generally check
WarrenTWarrenT
The best practice is to process the SQLCODEs you expect (as part of the expected processing) and to add exception code to handle the ones you don't. One implementation:
With this type of implementation you have to intentionally leave the loop; whether you've filled a subfile page, loaded the highest element in an array or hit an error. I'm not sure there is a single, generic implementation that will handle all circumstances. Sometimes you might want to leave the read loop if you have a record lock and sometimes you want to issue a message and try again (for example).
Buck CalabroBuck Calabro
I did some more searching on the topic and found something on IBM's site (quote):
Which would lead me to an
sql_found()
like this:That should take care of the End of Data condition and fail on all errors. I'm not sure if there are some warnings that I should take care of (don't want to get trapped in an endless loop, if there is a warning that leads to not reading).
kratenkokratenko5,51944 gold badges3030 silver badges5252 bronze badges