[go: up one dir, main page]

0% found this document useful (0 votes)
39 views19 pages

Getting Started With RPG

The document provides an overview of RPG, a business-oriented programming language that simplifies database interactions and business rule implementations. It discusses the evolution of RPG, its syntax, and features, emphasizing the advantages of using true decimal arithmetic over floating point. The document also highlights the ease of declaring variables, integrating databases, and writing functions in RPG, making it a powerful tool for business applications.

Uploaded by

Surya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
39 views19 pages

Getting Started With RPG

The document provides an overview of RPG, a business-oriented programming language that simplifies database interactions and business rule implementations. It discusses the evolution of RPG, its syntax, and features, emphasizing the advantages of using true decimal arithmetic over floating point. The document also highlights the ease of declaring variables, integrating databases, and writing functions in RPG, making it a powerful tool for business applications.

Uploaded by

Surya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

Getting

Started With

Agenda
• There isn’t enough time to teach a
whole programming language in this
session!
• But we can look at:
• Basic examples of the syntax
• How it makes your life easier
• What makes RPG a great business language
• A few powerful features of RPG
What is
• A business-oriented programming language
• Makes it very easy to work with databases, write business rules, work with
screens, and print reports.
• It does not stand for Report Program Generator.
• It used to -- however... In 1994 IBM changed it to officially not stand for anything!
• Even amongst season professionals, there is a lot of confusion about the
name, the "versions", and languages released.
• Versions are backward compatible, allowing code to move forward to new
versions when they are available.
• Very much under development, new enhancements released every spring
and fall. More than 30 major enhancements in the past 5 years.

Languages
Language Introduc Stopped
ed Enhancing/Supporting
FARGO 1959 IBM 1401 1960 / 1971
(Fourteen-O-One Automatic
Report Generation Operation)

RPG ("RPG I") 1960 IBM 1401 1971


(Report Program Generator)

RPG II 1968 IBM System/3, 34, 36, Mainframes, Others, 1988 / still supported
AS/400 with System/36 Environment
RPG III 1978 IBM System/38, AS/400, Windows, Others 1993 / still supported
RPG IV 1994 Windows, IBM i, Others still enhanced / supported

NOTE: The numbers I, II, III, IV are not properly known as "versions" – but different
languages. Each of the above has many different versions available.
Compilers
Compiler Language Nicknames
System/36 Compatible RPG II RPG II RPG/36
System/38 Compatible RPG III RPG III RPG/38
RPG/400 RPG III
Visual RPG (discontinued) RPG III VRPG
VisualAge for RPG (discontinued) RPG IV VARPG
ILE RPG for IBM i (formerly ILE RPG/400) RPG IV RPGLE, RPGILE, RPG/FREE

NOTE: Versions of the ILE RPG compiler that are still supported are 7.2, 7.3, 7.4
and 7.5. (Sometimes called V7R2, V7R3, etc)

Fixed vs Free-Format
C *INLR DOUEQ *ON dou *inlr = *on;

C WRITE INVINQ2F write INVINQ2F DSP2F;


C EXFMT INVINQ2C exfmt INVINQ2C DSP2C;
C MOVEL *BLANKS SCMSG scMsg = *blanks;

C *IN03 IFEQ *ON if *in03 = *on or *in12 = *on;


C *IN12 OREQ *ON leavesr;
C LEAVESR endif;
C ENDIF

C *IN25 IFEQ *ON if *in25 = *on;


C MOVE *OFF *IN25 *in25 = *off;
C EXSR OPENURL exsr openURL;
C ENDIF endif;

C *IN08 IFEQ *ON if *IN08 = *ON;


C MOVEL 'B' MODE mode = 'B';
C Z-ADD 2 STEP step = 2;
C LEAVESR leavesr;
C ENDIF endif;

C ENDDO enddo;

It surprises a lot of people who are new to RPG that these aren't different languages,
or even different versions of RPG. They are both compiled with the ILE RPG compiler,
both compatible with version 7.5, and both considered RPG IV!
Recommendation: Don't Bother Learning Fixed!
dou *inlr = *on;

write INVINQ2F DSP2F;


exfmt INVINQ2C DSP2C;
• Don't bother learning fixed format (until scMsg = *blanks;
you need it) if *in03 = *on or *in12 = *on;
• There are free tools to convert from fixed leavesr;
endif;
format to free
• Also, once you understand free format, it's if *in25 = *on;
*in25 = *off;
easy enough to read fixed format. exsr openURL;
endif;
• Code the new stuff in free.
if *IN08 = *ON;
mode = 'B';
step = 2;
leavesr;
endif;

enddo;

Hello World
snd-msg just writes an informational
snd-msg 'Hello World';
message.
*inlr = *on;
*inlr = *on ends the program.

**free **FREE allows us to start in column 1, and


make lines as long as we want.
dcl-s name varchar(30);
DCL-S declares a variable.
name = 'Scott Klement';

if %subst(name: 1: 5) = 'Scott'; IF <condition>;


snd-msg 'Hello, Scott!' ...stuff to do...
endif;
Endif;
*inlr = *on; Notice that there is a semicolon after the if
condition.
Declaring Variables
Variables in RPG are declared with a DCL-xxx keyword.

Most of the time, this means using DCL-S


• "declare stand alone variable"

Sometimes you declare data structures, prototypes, procedure interfaces, and other things.
• DCL-S = declare standalone
• DCL-C = declare constant
• DCL-DS = declare data structure
• DCL-F = declare file (database table, screen, printer, tape)
• DCL-PR = prototype (for calling other routines)
• DCL-PI = procedure interface (parameter interface to a routine)
• DCL-PROC = procedure/function

DCL-S <variable name> <data type> (length) keywords.

Declaring Variables
DCL-S <variable name> <data type> (length) keywords;

dcl-s Var1 char(10); // fixed-length 10 characters


dcl-s Var2 varchar(1234); // variable-length 1234 chars
dcl-s Var3 varchar(1234) ccsid(*utf8); // variable-length, but in utf-8
dcl-s Var4 ucs2(4321) ccsid(*utf16); // fixed-length but in utf-16

dcl-s Var5 packed(9: 2); // xxxxxxx.xx


// packed decimal 9 digits, 2 decimals
// (digits is the total incl the decimals)
// xxxxxxx.xx
dcl-s Var6 packed(18: 0); // xxxxxxxxxxxxxxxxx
dcl-s Var7 zoned(11: 3); // xxxxxxxx.xxx

dcl-s Var8 int(10); // 32-bit (10 decimal digits) integer


dcl-s Var9 float(8); // 64-bit (8 byte) floating point

dcl-s Var10 date; // date variable (default YYYY-MM-DD format)


dcl-s Var11 date(*usa); // date variable in MM/DD/YYYY format
dcl-s var12 time; // time variable
dcl-s var13 timestamp; // date+time variable
DCL Keywords
• CCSID = character set of the variable (special values *utf8 and *utf16 for Unicode)
• INZ = initialize (set the initial variable value)
• LIKE = variable is the same data type/length as another variable
• LIKEDS = variable is like a data structure
• Many others exist – I won't try to name them all here!

dcl-s Var3 varchar(1234) ccsid(*utf8);


dcl-s Var4 ucs2(4321) ccsid(*utf16);

dcl-s Var4 ucs2(4321) ccsid(*utf16);


There are many DCL keywords
dcl-s Var5 packed(9: 2);
dcl-s price like(Var5) inz(10.45); and an endless list of things you
can do with them – they are a
dcl-ds Name_t;
super powerful feature of RPG!
FirstName varchar(15) inz('Scott');
LastName varchar(15) inz('Klement');
end-ds;

dcl-ds OtherName likeds(Name_t) inz(*likeds);

Why is RPG Good For Business?


• Strictly-typed variables allow you to catch more potential errors at
compile-time.
• This prevents bad data from getting into your system.
• DCL keywords make it easy and powerful

• True decimal arithmetic.


• Database is better integrated into the language.
• Easy to build full-screen applications
• Easy to work with date, time and timestamp (date+time) variables.
• Easy to work with REST APIs, XML, JSON
Floating Point vs. True Decimal Math

RPG supports true decimal arithmetic, whereas


most programming languages using floating point
numbers.

Why does this matter?


=1*(.5-.4-.1)

Consider this Excel formula. What do you expect the


result to be?

Excel uses floating point – like most programming


languages – and is prone to the same problems.

Floating Point vs. True Decimal Math


It should've been 0.
But all numbering systems (decimal, binary, hex,
etc) represent certain fractions with repeating
numbers.

In decimal, 1/3 is 0.33333333333 (repeats


forever).

But the computer can't store an infinite number


of decimal places – so it has to round it off at
some point.

The numbers that cause this in binary are


different than the ones in decimal – but the
same problem exists.

As a business that serves humans – it's better to


round off in decimal, since that's what people
expect.

RPG works in decimal numbers, not binary.


Floating Point vs. True Decimal Math
#include <stdio.h> public class numbers2 {
public static void main(String[] args) {
int main(int argc, char **argv) {
double result;
double result;
result = 1*(.5-.4-.1);
result = 1*(.5-.4-.1); System.out.println(String.format("%26.25f", result));
printf("%26.25f\n", result);
}
return 0;
} }

To prove my point, here are examples in both C and Java. (Other languages
are similar – even RPG would do the same if you forced it to use floating
point math)

In all cases, they print the following (same as Excel):


-0.0000000000000000277555756

How Does That Affect Business?


Is it okay for your business to have values that are slightly off?
• Payroll
• Revenue
• Inventory
• Quantity shipped to a customer
RPG Packed vs. Zoned
Packed and Zoned are both numeric data types.
dcl-s result1 packed(9: 2);
dcl-s result2 zoned(9: 2);
• Difference is how they're stored in
memory.
result1 = 1*(.5-.4-.1); • Packed is a form of "binary coded
decimal", typically uses ½ the memory
result2 = 1*(.5-.4-.1); of zoned.
• But zoned is easier to read if you see the
raw unformatted value in memory.
snd-msg %char(result1);
snd-msg %char(result2);
In both cases, you specify the size as a number of
digits and decimal places.
*inlr = *on;
But they are "true decimal" types, not subject to
binary rounding
This will print:
0.00
0.00

Loops
**Free DOW = Do While

dcl-s X int(10); Pretty much the same as a while loop in any


other language.
dow X > 0;
// do something
enddo;

DOU = Dou Until (condition is checked at the


dou X = 0; 'enddo', so loop is always done once)
// do something
enddo;
For Loops

for x = 1 to 10; Loop through a range of numbers


// do something
endfor;

Loop through the items in an array


for element in array;
// do something
endfor;

Loop through a fixed set of arbitrary valuesv


for item in %list('Item1': 'Item2': 'Item3');
// do something
endfor;

I'm just scratching the surface of what the different types of loops can do –
just to give you a feel for it.
There are many, many, many more options available!

Sub-Procedures ("functions")
name = MyProcedure(last: first);
snd-msg name; You can write your own functions and make
them available within the current program.
. . . other stuff could be here . . . Or export them to make them available to
other programs as well.
dcl-proc MyProcedure; RPG calls them "sub-procedures".

dcl-pi *n;
last varchar(15) const; Notice that RPG's built-in functions always
begin with a % character. The functions you
first varchar(15) const; write cannot begin with that character.
end-pi;
This makes it easy to distinguish the origin of a
function, and also makes it easy to avoid
dcl-s fullname varchar(30); naming clashes.

fullname = first + ' ' + last;


return fullname;

end-proc;
Integrated Database
DCL-F (declare file)
dcl-f CUSTFILE disk keyed;
• Declares a database table
CUSTNO = 1500; • keyed = Allows keyed (indexed) access.
chain CUSTNO CUSTFILE; • Automatically declares variables for all of
the columns ("fields") in the table ("file").

// the CUSTFILE database table contains columns named • CHAIN = loads a record by it's key.
// CUSTNO, NAME, CONTACT, STREET, CITY, STATE, POSTAL
// and BALANCE -- all are ready to use!

Integrated Database – Java Comparison 1/3


In most other languages (Java, in this
example) you have to:
import java.sql.*; • Import a database driver
import com.ibm.as400.access.AS400JDBCDriver;
• Use it to connect to the database
public class JavaTest { • Build an SQL statement in a character string
public static void main(String[] args) { • Run the statement
• Read the results into columns
try {
// Load driver • Clean up after the statement

Class.forName("com.ibm.as400.access.AS400JDBCDriver"); • Close the connection

// connect to database

String jdbcUrlFmt = "jdbc:as400://localhost;user=%s;password=%s;naming=system;";


String jdbcUrl = String.format(jdbcUrlFmt, Credentials.user, Credentials.password);

Connection conn = DriverManager.getConnection(jdbcUrl);


Integrated Database – Java Comparison 2/3
PreparedStatement stmt = conn.prepareStatement("select CUSTNO, NAME, CONTACT, "
+ "STREET, CITY, STATE, "
+ "POSTAL, TITLE, BALANCE "
+ "from CUSTFILE "
+ "where CUSTNO=?");
stmt.setInt(1, 1500);

ResultSet rs = stmt.executeQuery();
while (rs.next()) {

int CUSTNO = rs.getInt ("CUSTNO");


String NAME = rs.getString("NAME");
String CONTACT = rs.getString("CONTACT");
String STREET = rs.getString("STREET");
String CITY = rs.getString("CITY");
String STATE = rs.getString("STATE");
String POSTAL = rs.getString("POSTAL");
double BALANCE = rs.getDouble("BALANCE");

// Do something with the column values

Integrated Database – Java Comparison 3/3


rs.close();
conn.close();
}
catch (Exception e) {
System.out.println(e.getMessage());
}

Or, in RPG:
dcl-f CUSTFILE disk keyed;
The bulk of work in a business application is
CUSTNO = 1500; calculations and database:
chain CUSTNO CUSTFILE;
• True decimal arithmetic
if %found; • Easier database operations
// do something with the column values
endif;
NOT FAIR! Not an Apples-To-Apples Comparison
dcl-ds CUSTFILE ext end-ds;
dcl-s output varchar(500);

CUSTNO = 1500; RPG's proprietary native I/O isn't totally


equivalent to SQL. SQL is more modern and
exec sql can do many more things.
declare rs cursor for
select CUSTNO, NAME, CONTACT, STREET, CITY, STATE, So let's compare the same example with using
POSTAL, TITLE, BALANCE
SQL in RPG.
from CUSTFILE
where CUSTNO = :CUSTNO;

exec sql open rs;


Or, in RPG:
exec sql fetch next from rs into :CUSTFILE;

dow sqlcode = 0; Notice the use of :CUSTNO instead of ?. This


makes the code much more readable.
// Do something with the column values
Also, notice the SQL is not built in a string.
exec sql fetch next from rs into :CUSTFILE; This lets the compiler & IDE detect errors in
enddo; your syntax.

exec SQL close rs;


It also makes the coding a lot easier, no need
to concatenate values (unless you want to),
just type what you want.

Easy Dates/Times
Just a quick example.

You can easily add or subtract days, months,


years, etc.
**Free Or hours, minutes, seconds, etc from a time.
This type of logic is very common and
dcl-s DeliveryDate date(*usa); necessary in business!
dcl-s output varchar(80);
dcl-s LeadTime int(10);

LeadTime = 14;
DeliveryDate = %date() + %days(LeadTime);

output = 'Delivery Date = ' + %char(DeliveryDate);


snd-msg output;

*inlr = *on;
Screens Are Easy
For basic text screens
• IBM provides an easy-to-use WYSIWYG
screen editor, where you can build your
screens using drag/drop, etc.
• Then you refer to these screens as "files" in
your program.

Screens Are Easy For basic text screens

dcl-f INVINQ2D workstn INDDS(dspIndMap); • EXFMT = "execute screen format".


• User can use the screen until they press
... more code here ... ENTER or a function key.
• Then control comes back to the program.
dou DSP1.MSG = *BLANKS;

exfmt INVINQ1 DSP1; // Displays the screen


DSP1.MSG = *BLANKS;

if EXIT or CANCEL;
return QUIT;
endif;

if DSP1.INVNO <= 0;
DSP1.MSG = 'Please enter an invoice number!';
iter;
endif;

enddo;
Reports Are Easy Very much like screens, IBM provides a GUI
tool to create reports.
You then refer to the report as a file in your
RPG code.
In this case, I laid out the variable data for an
invoice.

Reports Are Easy


dcl-f INVOICE PRINTER oflind(overflow) usage(*output)
usropn;

setll (myInvNo) INVDET;


reade (myInvNo) INVDETF;

write HEADING;

dow not %eof(INVDET);

lineamt = %dec(qty * price: 9: 3);

if overflow;
write FOOTER;
write HEADING;
first = *on;
endif;
write DETAIL; The fixed headings and graphical elements of
the invoice were designed in Microsoft Word
reade (myInvNo) INVDETF; – I then told it to generate an "overlay".
enddo;
The overlay gets merged with the data from
write FOOTER; the printer file to make this invoice.
Easy REST APIs
To write a quick & dirty REST API, all you need
Ctl-Opt DFTACTGRP(*NO) ACTGRP('WEBAPI') PGMINFO(*PCML:*MODULE); to do is write a program that gets it's
Dcl-F CUSTFILE Usage(*Input) Keyed PREFIX('CUST.');
input/output through parameters.

Dcl-DS CUST ext extname('CUSTFILE') qualified End-DS;


The operating system provides a tool called
Dcl-PI *N;
CustNo like(Cust.Custno); "Integrated Web Services" that can be
Name like(Cust.Name); configured to call this program.
Street like(Cust.Street);
City like(Cust.City);
State like(Cust.State);
Postal like(Cust.Postal);
It will handle all of the communications work,
End-PI; converting data between JSON or XML and
the parameters, etc.
Dcl-PR QMHSNDPM ExtPgm('QMHSNDPM');
MessageID Char(7) Const;
QualMsgF Char(20) Const;
MsgData Char(32767) Const options(*varsize);
MsgDtaLen Int(10) Const;
MsgType Char(10) Const;
CallStkEnt Char(10) Const;
CallStkCnt Int(10) Const;
MessageKey Char(4);
ErrorCode Char(8192) options(*varsize);
End-PR;

31

Easy REST APIs


Dcl-DS err qualified;
bytesProv Int(10) inz(0);
This API simply returns a customer's address
given a customer number.
bytesAvail Int(10) inz(0);
End-DS;

Dcl-S MsgDta Varchar(1000); The QMHSNDPM routine sends an error when


Dcl-S MsgKey Char(4); the customer wasn't found. (This is an older
Dcl-S x Int(10); example, a newer one might use SND-MSG to
do the same thing.)
chain CustNo CUSTFILE;
if not %found;
msgdta = 'Customer not found.';
QMHSNDPM( 'CPF9897': 'QCPFMSG *LIBL': msgdta: %len(msgdta): '*ESCAPE'
: '*PGMBDY': 1: MsgKey: err );
else;
Custno = Cust.Custno;
Name = Cust.name;
Street = Cust.Street;
City = Cust.City;
State = Cust.State;
Postal = Cust.Postal;
endif;

*inlr = *on;
32
Handling XML or JSON Yourself
If you need to process XML or JSON from a
Ctl-Opt OPTION(*SRCSTMT: *NODEBUGIO) DFTACTGRP(*NO); file, parameter, or other means (aside from
the Integrated Web Services) or if you want to
Dcl-F CUSTFILE Usage(*Input) Keyed prefix('CUST.');
write the API yourself without a special tool,
dcl-ds CUST ext extname('CUSTFILE') qualified end-ds;
it's relatively easy to do.
Dcl-PR getenv Pointer extproc('getenv');
var Pointer value options(*string);
End-PR; RPG provides a built-in way to map XML or
JSON to an RPG variable called DATA-INTO. (or
dcl-s custno like(CUST.custno); the older XML-INTO.)
Dcl-S pos int(10);
Dcl-S uri varchar(1000);
Dcl-S json varchar(1000); Likewise, it can generate XML or JSON using
Dcl-C ID1 '/cust/'; another tool called DATA-GEN.
Dcl-C ID2 '/custinfo/';

dcl-ds failure qualified;


error varchar(100);
end-ds;

33

Easy REST APIs


uri = %str(getenv('REQUEST_URI')); In this example, the CUSTFILE database table
is automatically loaded into the CUST data
monitor; structure.
pos = %scan(ID1: uri) + %len(ID1);
custno = %int(%subst(uri:pos)); DATA-GEN is being used to convert the data
on-error; structure to JSON format and write it out.
failure.error = 'Invalid URI';
DATA-GEN failure %DATA(json) %GEN( 'YAJLDTAGEN'
: '{ "http status": 500, "write to stdout": true }'); As with most everything in this presentation, I
return; am just scratching the surface! This
endmon; functionality is full of loads of different
features and options to make it extremely
chain custno CUSTFILE; versatile!
if not %found;
failure.error = 'Unknown customer number';
DATA-GEN failure %DATA(json) %GEN( 'YAJLDTAGEN'
:'{ "http status": 500, "write to stdout": true }');
return;
endif;

DATA-GEN cust %DATA(json) %GEN( 'YAJLDTAGEN'


:'{ "http status": 200, "write to stdout": true }');
return;

34
Rich Community of Developers and Tools
Although this session focuses on what's in RPG itself, it's worth mentioning the huge
community of developers and tools out there:

• People in this community like helping each other!


• We are very close knit!
• Rich world of open source tools to help you (including things like Git and Jenkins)

• Vendors provide tools that make a lot of this stuff even easier... I can't list them all, but
some of my own are:
• MDCMS = Change Management / devops / agile
• MDREST4i = Easier APIs

• PROFOUND UI (previous job) make GUI web-based screens just as easily as text based ones.
• Many other vendors offer these types of things – lots of good choices available!

35

Recommended Resources:

• IBM Docs – the official source of documentation:


(online books, official IBM manuals)
Programming / ILE Languages / RPG

• Programming in ILE RPG (5th Edition) by Jim Buck & Bryan Meyers
(in-depth book with exercises, 664 pages)
https://www.amazon.com/Programming-ILE-RPG-Jim-Buck/dp/1583473793

• COMMON Bootcamp: Programming in ILE RPG


(getting started video -- no charge to COMMON members!)
http://www.common.org/education-events/boot-camp-training/programming-ile-rpg

• imPOWER Technologies
(instructor-led online courses)
https://impowertechnologies.com
Questions?

For this presentation visit my web site:

http://www.scottklement.com/presentations/

You might also like