Tumgik
worksofbarry Ā· 8 years
Text
RPGLE - Manual Memory Management
This is quite a new topic for me, but over the last few days I've been using them more and more so I thought I'd write about it. In this blog I will be using STRDBG since I recently stopped using Rational Developer for i for development.
In this, we'll talk about allocating space for null-terminated strings in RPG. It's going to cover the Pointer type, %Alloc, Dealloc and %Str
Pointer Type
The pointer type is quite simple. It holds a value which points to somewhere in memory. When you define a pointer, the initial value will be *Null.
Next, I'm going to compile this program and start debugging it so we can see what a pointer value looks like.
Dcl-S Text Char(32); Dcl-S Pointy Pointer Inz(*Null); //I could of also used Inz(%Addr(Text)) Text = 'Hello WorksOfBarry blog!'; Pointy = %Addr(Text); //Breakpoint here. *InLR = *On; Return;
When you STRDBG this program, make sure you put a breakpoint after the comment says:
> EVAL Pointy POINTY = SPP:D9858621D4002540 > EVAL Pointy:c 20 POINTY:c 20 = 'Hello WorksOfBarry b' //This shows the next 20 bytes from the pointer //(:c for characters, 20 for length)
%Alloc and Dealloc
I've found that some people find memory allocation can be really confusing, but personally I find it very simple.
Just some things to remember:
When you allocate space, it will allocate within a heap inside of the program's activation group.
You are able to pass pointers to programs which run in different activation groups to access heaps in different activation groups.
If you forget to deallocate memory, all memory within the activation group is deallocated when it ends.
%Alloc takes one parameter, which is a numeric length. I have found that if you're using alloc to work with strings, you should add one to your length. This is to support the null terminator.
Let's take my name for example, which is "Liam Allan". That's 10 characters, including the space, which is 10 bytes - but we need to have an extra byte for the null terminator.
Deallocating is very important. The dealloc operation allows you to deallocate the memory you have allocated and has two extenders:
E for error. If this extender is used, dealloc will never crash and will instead update the value of %Error.
N for *Null. This means that when the memory is deallocated, it will set the pointer back to *null.
I like to use both!
Here's a working example:
Dcl-S Pointy Pointer Inz(*Null); Pointy = %Alloc(11); Dealloc(ne) Pointy;
%Str
Great! So now we know how to create space, how do we use this space? With %Str of course! %Str has two uses - to make this simple, it can be used as a getter and setter.
Setter
The setter should take a second value, which is the length you're assigning - it does not have to match the length, it's just preference for me. Just know that the last character will always be the null terminator.
Dcl-S Pointy Pointer Inz(*Null); Pointy = %Alloc(11); %Str(Pointy:10+1) = 'Liam Allan'; //Notice the +1 for null-terminator Dealloc(ne) Pointy;
Getter
Getting the value out is nice and simple. One thing to remember is that %Str will get all characters at the pointer up until the null-terminator.
You can also pass in a second parameter, which is the length to get - in this example I will use length of the text I assigned when printing with Dsply.
Dcl-S Name Char(10); Dcl-S Pointy Pointer Inz(*Null); //Allocate and assign Pointy = %Alloc(11); %Str(Pointy:%Len(Name)+1) = 'Liam Allan'; //Give Name field a value Name = 'Liam Allan'; If (%Str(Pointy) = Name); DSPLY %Str(Pointy:10); ENDIF; Dealloc(ne) Pointy;
End
Well I hope this was a somewhat interesting guide into null-terminator strings and pointers. I actually had fun writing it!
2 notes Ā· View notes
worksofbarry Ā· 8 years
Text
RPGLE - Uppercase in one line (Embedded SQL)
I've just seen this blog post and I do only have a two issues with it:
For code that's written in 2016, it's still in fixed format.
It's so much code just to do an upper case that supports multiple CCSIDs.
In this small blog, I'm going to show you how to do 'uppercase' in one line of code - using Embedded SQL.
Dcl-S CharField Char(100); CharField = 'hello db2 summit!'; EXEC SQL SET :CharField = UPPER(:CharField);
..and that's it.
2 notes Ā· View notes
worksofbarry Ā· 8 years
Text
Calling ILE (RPGLE, C, CPP, COBOL) programs from SQL (Node/PHP/Python)
In today's blog, we're going to talk about stored procedures to call ILE programs from SQL. I've been inspired to write this blog because of an article: Recycling RPG as Stored Procedures, which was written by Susan Gantner and Jon Paris. Although fairly old, it's still a great article.
This article is based on IBM i 7.2. The plan is to go over creating the program, creating the SQL procedure and then also creating a Node.js script to call that procedure.
Creating the RPG Program
I use RPG by pure example. You could use any ILE language, even Java. Also, pCusAge could be Int(3) instead.
**FREE Ctl-Opt DftActGrp(*No) ActGrp(*New); Dcl-Pi Program; pCusID Int(10); pCusName Char(20); pCusEmail Char(25); pCusAge Int(10); END-PI; Select; When (pCusID = 1); pCusName = 'Barry'; pCusEmail = '[email protected]'; pCusAge = 19; When (pCusID = 2); pcusName = 'MillyMai'; pCusEmail = '[email protected]'; pCusAge = 19; When (pCusID = 3); pcusName = 'DarthJim'; pCusEmail = '[email protected]'; pCusAge = 41; When (pCusID = 4); pcusName = 'Lizzo'; pCusEmail = '[email protected]'; pCusAge = 48; ENDSL; *InLR = *On; Return;
Quite simply, you pass in data though the first parameter and the program will pass data out through the other paramaters (by reference). I call this program Program and placed it in my current library, which is #LALLAN. (#LALLAN.PROGRAM)
Creating the stored procedure
I use ACS->Run SQL Scripts to run this SQL statement, but you can probably use STRSQL if you wanted to. The following statement creates a stored procedure named getCusInfo in my #LALLAN library.
CREATE OR REPLACE PROCEDURE #LALLAN.getCusInfo ( IN CusID INTEGER, OUT CusName CHAR (20), OUT CusEmail CHAR(25), OUT pCusAge INTEGER ) EXTERNAL NAME #LALLAN.PROGRAM LANGUAGE RPGLE PARAMETER STYLE GENERAL
Using Node.js to call our SQL procedure
In this Node.js script, we use prepared statements to pass in data. The data comes out of the executeSync callback function (the first parameter). The script works in this order:
Define db which points to the DB2 API for Node.js
Create the SQL statement (sql)
Create a new DB2 connection instance (dbconn) and then connect to the *LOCAL database
Define a prepared statement (stmt)
Prepare our SQL statement (sql variable) to our prepare statement instance (stmt) using stmt.prepareSync
Bind the parameters with stmt.bindParamSync
Execute the prepared statement with stmt.executeSync
I put the following code into nodeDb2.js in my current directory, but you can call it whatever you like.
var db = require('/QOpenSys/QIBM/ProdData/OPS/Node4/os400/db2i/lib/db2a'); //Create out statement var sql = "call #LALLAN.getCusInfo(?, ?, ?, ?)"; //Prepare our connection var dbconn = new db.dbconn(); dbconn.conn("*LOCAL"); //Create out prepared statement var stmt = new db.dbstmt(dbconn); //Our customer object/array var Customer = []; Customer.ID = 1; Customer.Data = []; stmt.prepareSync(sql); stmt.bindParamSync([ [Customer.ID, db.SQL_PARAM_INPUT, 2], ['', db.SQL_PARAM_OUTPUT, 1], ['', db.SQL_PARAM_OUTPUT, 1], [0, db.SQL_PARAM_OUTPUT, 0] ]); stmt.executeSync(function callback(out) { Customer.Data = out; }); console.log(Customer.Data); // delete stmt; dbconn.disconn(); delete dbconn;
Testing the process
I've stopped using QSH and have started using SSH to log into my system when using Node.js. I call the script with node nodeDb2.js and my output is a little something like this:
C:\Users\Barry\Documents\GitHub> ssh barry@swagibmi -bash-4.2$ node nodeDb2.js [ 'Barry ', '[email protected] ', '19 ' ]
If I was to change my Customer.ID in my Node.js script to 2, 3 or 4, the output would have been something else.
Extra: Calling the SQL procedure from PHP!
Thanks to @phpdave (godzillai5.wordpress.com) for writing this script. This script will function the same as the Node.js one would - processes the statement, but instead puts the data back into the $Customer class.
<?php //Create db connection $hostname = "MYIBMI"; $user = "MYPROFILE"; $password = ""; $dbconn = new PDO("odbc:" . $hostname, $user, $password); //SQL to run stored proc $sql = "call #LALLAN.getCusInfo(?, ?, ?, ?)"; //Prepare SQL for execution $stmt = $dbconn->prepare($sql); //Create a test object for demo purposes $Customer = new stdClass(); $Customer->ID = 1; $Customer->Data1 = ""; $Customer->Data2 = ""; $Customer->Data3 = 1; //Bind object properties to our object $stmt->bindParam(1, $Customer->ID, PDO::PARAM_INT); $stmt->bindParam(2, $Customer->Data1, PDO::PARAM_INPUT_OUTPUT); $stmt->bindParam(3, $Customer->Data2, PDO::PARAM_INPUT_OUTPUT); $stmt->bindParam(4, $Customer->Data3, PDO::PARAM_INPUT_OUTPUT); //Run it $stmt->execute(); //Dump our object to the screen to see what everything got set to. //Or alternatively run xdebug or another debugger to view the //$Customer object after execution var_dump($Customer); ?>
1 note Ā· View note
worksofbarry Ā· 8 years
Text
RPGLE - Creating and writing to spool files
I found out recently that it's so simple to create and write to spool files. Why you would you want to write to spool files, you may ask. I want spool files to be written to as logs. For example, with Relic Package Manager, you have an option to print the log to the screen as a build happens - or instead to print it to a spool file (useful with SBMJOBs).
There really is only four lines that we need to declare, open, write and close. Oh, we also need to delcare a data structure since WRITE only accepts a data structure with single subfield of Char(132) in this instance - I have no idea why, but seems very odd.
Dcl-F QsysPrt Printer(132) UsrOpn; is used to declare a printer.
Dcl-Ds gLine; *N Char(132); End-Ds;
We need this DS as the Write opcode only accepts a DS. Notice that the length of the subfield is the same length as the Printer in declaration of QsysPrt.
Open QsysPrt; is used to open the printer, which actually creates the spool file.
Write QsysPrt gLine; writes a line to the spool file. Note that if gLine is *BLANK nothing will write.
Close QsysPrt; closes the spool file, ending the ability to write.
Program example
Let's take this example program
Dcl-F QsysPrt Printer(132) UsrOpn; Dcl-Ds gLine; *N Char(132); End-Ds; //****************** Open QsysPrt; gLine = 'Spool file line 1'; Write QsysPrt gLine; gLine = 'Spool file line 2'; Write QsysPrt gLine; gLine = 'Spool file line 3'; Write QsysPrt gLine; gLine = ''; Write QsysPrt gLine; gLine = 'Spool file line 5'; Write QsysPrt gLine; Close QsysPrt; *InLR = *On; Return;
After you have compiled this code (I called my program TEST1) you can call it (CALL TEST1), which should result on something on your user OUTQ - at least mine did. You should notice that the name of the spool file is what we named our declared file in the RPG program and that the User Data is the name of the program.
If you use 5 to display against the spool file, the output should be what you had written in your program.
That's it! I hope this helped you in developing some useful tool you're making.
If you're interesting in reading more on this subject, Ted Holt had providied me with links to these ITJungle articles:
Quick And Handy RPG Output
Quick And Handy RPG Input
1 note Ā· View note
worksofbarry Ā· 8 years
Text
Whatā€™s happening??
So I work from home now. I haven't written a blog in ages, so this is a bit more about where I'm at and where I'll be going.
Job
I work at Profound Logic Software as a Product Developer. They are based in the US and I am based in the UK, so this does mean I work from home. I pay my own taxes now.. it's a lot easier than I had imagined and it does also technically mean I'm a contractor to Profound Logic. I can confirm, I enjoy working from home but do miss spending time at the Profound Logic offices. Working from home means I can eat more, really. That's the only downside so far, is that I am eating more; but I have also started running since I wasn't doing any exercise. Work is going well. Absolutly loving the project I am working on and I feel like I am part of a team.
Speaking
I have a lot of travelling coming up in October.
RPG & DB2 Summit in Chicago - I'll be speaking about Embedded SQL (RPG) for web services and Open-Source ILE concepts
COMMON Belgium in Eindhoven, Netherlands - I'll be speaking about Open-Source ILE concepts. My girlfriend will be joining me on this trip too!
IBM Power Systems & Storage Technical University in London, United Kingdom - speaking subjects are the same as the RPG & DB2 Summit
Profound Logic User Seminar in Columbus, Ohio (November) - I'll be with Alex Roytman and we're talking about the new Profound.js project I'm so adamant about.
I have a very busy schedule, so hopefully my sleeping pattern holds up.
End
Well, that's about it for what's going on in my life right now. I was in IBM Systems Magazine in the SNAPSHOT section, so really big thanks to them for asking. I have an apartment viewing tomorrow with my girlfriend, but it's not too big of a deal.
Hope everyone is well!
2 notes Ā· View notes
worksofbarry Ā· 8 years
Photo
Tumblr media
I've spent the last week in Orange County, California with another week to go. Although my second time in the States now, it has been the biggest culture shock yet. Longer blog post to come when I am back in the UK.
3 notes Ā· View notes
worksofbarry Ā· 8 years
Photo
Tumblr media
I am currently in Dayton, Ohio and Iā€™ll be going to Orange County, California next week. Iā€™m travelling to these places to start at Profound Logic Software as a Software Developer. Exciting times ahead.
1 note Ā· View note
worksofbarry Ā· 8 years
Text
RPGLE - Web Requests with Embedded SQL
Once again I write another blog post about how great I find embedded SQL within RPG - this time we talk about web requests. This isn't really much of a blog post either.. it's really just a 'text version' of a session I am giving at the RPG and DB2 Summit.
These are the things we're going to look at:
SQLTYPE
HTTPGETCLOB
HTTPPOSTCLOB
Not a massive list, but a lot to talk about.
SQLTYPE
SQLTYPE is a new keyword in RPG for when you're declaring variables.. only really useful if you're using Embedded SQL in your programs. When the SQLTYPE keyword is used, it secretly creates a data structure under the covers (but only for certain SQL types)
These are some of the available types:
CLOB
CLOB_LOCATOR
CLOB_FILE
BLOB
BLOB_LOCATOR
BLOB_FILE
DBCLOB_LOCATOR
DBCLOB_FILE
The list could go on..
So this makes the syntax Dcl-S gSQLVar SQLTYPE([SQLTYPE]:[len]);.
When I say 'creates a data-structure' - I mean it really does. Take a look at this diagram:
HTTPGETCLOB
HTTPGETCLOB has two parameters. The first is the URL which it will send the request to and the second are the headers you want to give the request You can read more about the headers parameter here in the 'Sending customized HTTP header values' section.
In this 'get clob' example, I send a simple GET request to a URL (which you can replace with a host variable) and it will give the response back. It's pretty neat! Notice that when we declare our CLOB, we also give it a type.
Dcl-S WebResponse SQLTYPE(CLOB:256); Exec SQL SET :WebResponse = SYSTOOLS.HTTPGETCLOB ('https://api.bitcoinaverage.com/ticker/EUR/','');
If you debug this statement in STRDBG, after you've steped through it you can do eval WebResponse_Data to view the response and eval WebResponse_Len to view the length of the response.
You can do this same SQL statement within an SQL client (Run SQL Scripts in ACS or STRSQL..): SELECT SYSTOOLS.HTTPGETCLOB('https://api.bitcoinaverage.com/ticker/EUR/', '') FROM SYSIBM.SYSDUMMY1
HTTPPOSTCLOB
HTTPPOSTCLOB is kinda like HTTPPOSTCLOB, but with the 'post clob' you get an extra parameter which allows you to pass the body of the request (which makes it a POST request).
I like to keep my code quite tidy, so I have my response variable (gData) and I usually have a data structure to store the URL, header and body of the request in - then we initialize them with the relevant data for the request.
Dcl-S gData SQLTYPE(CLOB:2000); Dcl-Ds Request Qualified; URL Char(128); Head Char(1024); Body Char(1024); END-DS; Request.Body = '<?xml version="1.0" encoding="UTF-8" ?>' + '<soap:Envelope xmlns:soap=' + '"http://schemas.xmlsoap.org/soap/envelope/" ' + 'xmlns:xsi=' + '"http://www.w3.org/2001/XMLSchema-instance" ' + 'xmlns:xsd=' + '"http://www.w3.org/2001/XMLSchema" ' + 'xmlns:wiz="http://wizard.ws">' + '<soap:Body>' + '<thing:addressInput>' + '<Locale>pl</Locale>' + '<ServiceAddressId>0</ServiceAddressId>' + '<AccountNumber>1234</AccountNumber>' + '<MemoOpenDate>2016-01-01</MemoOpenDate>' + '</thing:addressDetailInput>' + '</soap:Body>' + '</soap:Envelope>'; Request.Head = '<httpHeader>' + '<header name="Content-Type" ' + 'value="text/xml;charset=UTF-8" />' + '<header name="Content-Length" value="' + %Char(%Len(%TrimR(Request.Body))) + '" />' //Length of the body + '<header name="Accept-Encoding" value="gzip,deflate" />' + '</httpHeader>'; Request.URL = 'http://yourserver:1234/SomeWS/SomeWebServices'; EXEC SQL SET :gData = SYSTOOLS.HTTPPOSTCLOB( :Request.URL, :Request.Head, :Request.Body );
If you then debug this EXEC SQL statement and eval gData you'll see the response length and the actual response:
Well I hope this generally a useful post.. I will go into a lot more detail during the session - this is just the basics.
2 notes Ā· View notes
worksofbarry Ā· 8 years
Text
RPGLE - Embedded SQL error handling
Following on from the last blog, this one will extend your Embedded SQL knowledge. This blog will mainly focus on two things. First: SQLSTATE and how to use it to your advantage. Second: Dynamic SQL queries in Embedded SQL
SQLSTATE is define as a Char(5), although for this tutorial we're only really interested in the first 2 characters (%Subst(SQLSTATE:1:2)). You can find out what those two character codes mean here. We're going to look at the following (for this tutorial):
00 Unqualified Successful Completion It works! 01 Warning Something broke(d)! 02 No Data Couldn't find the data you wanted
I also want to let you know, if you plan on debugging embedded SQL which affects a physical file in a *PROD library, make sure you STRDBG with UPDPROD(*YES) otherwise you'll get some weird SQLSTATE like 42 or 54. When you're debugging Embedded SQL and something goes wrong, always EVAL SQLSTATE and then DSPJOBLOG.. Embedded SQL will always print to the job log if you're debugging.
Back to the blog; In the previous blog, I used the following as an example:
Exec SQL SELECT CUS_BAL, CUS_NAME INTO :Customer.CUS_BAL, :Customer.CUS_NAME FROM CUSTOMERS WHERE CUS_ID = 1; printf(Customer.CUS_NAME + x'25');
But what if there is an error? At the moment, we're just printing Customer.CUS_NAME no matter what happens. Let's handle that using some of the 2 character codes we'd spoken about earlier. I'm using a SELECT and WHEN to check the value of gSql. gSql is defined like so and we only assign to gSql after we have used EXEC SQL statements. You may want to replace the static strings with constants.
Dcl-S gSql Char(2); //Embedded SQL happens here gSql = %Subst(SQLSTATE:1:2); Select; When (gSql = '00'); printf(Customer.CUS_NAME + x'25'); When (gSql = '01'); printf('Probably worked, but with warnings. ' + 'Check job log?' + x'25'); When (gSql = '02'); printf('No relevant data' + x'25'); Other; printf('It''s worse: ' + gSql + x'25'); ENDSL;
I know it seems basic, but this type of validation may allow you to handle issues better - even display nice popups to say that no data was found.
2 notes Ā· View notes
worksofbarry Ā· 8 years
Text
RPGLE - Starting off with Embedded SQL
I love Embedded SQL in RPG, it's my favourite feature and it couldn't be any better really (well it could, but this isn't a rant). This long blog post is actually going to be more of a guide.
Embedded SQL is going to make your code cleaner, and also process more workload in less lines of code. No more Dcl-F.. Embedded SQL is here to replace it.
I'd like to note, Embedded SQL should not be used to modernize code. If you have business logic using delcared files, do not remove it. Embedded SQL should be used to write new logic in new software.
How does Embedded SQL work?
Interesting topic, this. I like how it works because I have an interest in compilers, others may find it boring - but it's interesting to know.
Embedded SQL takes your source member, scans it for the EXEC SQL operation(?) and replaces it with fixed format RPG (sigh) program calls. I/some call this step the 'pre-compile' - it's what the pre-compiler does. The pre-compiler also declares a load of variables for your use in programs, like SQLSTATE for example.
I use SQLSTATE to check if there are any data errors or SQL errors. SQLSTATE is a character five field, and you can find what the data means here.
How do I start using it?
The first step is to ditch CRTBNDRPG and CRTRPGMOD. They are now useless in my mind, as you can use CRTSQLRPGI as a replacement for both of these. Also, start using SQLRPGLE as the extention for all your RPG code.
To create a regular program, you use CRTSQLRPGI with OBJTYPE(*PGM) as a parameter; for a module you use OBJTYPE(*MODULE). This is just my opinion though, of course you can still use the other commands, but you can still compile regular RPG with this command.
For this post, I'm gonna use this SQL to create a new physical file/table. Now, as naughty as I am: I did use STRSQL to create this table. I typed create table and used F4 to prompt the rest of the data in. LIAMALLAN1 is the library I made the PF in, but it's optional of course.
CREATE TABLE LIAMALLAN1/CUSTOMERS ( CUS_ID INT NOT NULL WITH DEFAULT, CUS_BAL NUMERIC (11 , 2) NOT NULL WITH DEFAULT, CUS_NAME CHAR (25) NOT NULL WITH DEFAULT, CUS_EMAIL CHAR (50) NOT NULL WITH DEFAULT )
This is not an SQL tutorial, but we do want data in the file. You can optionally use UPDDTA against the PF with insert mode to add data - or you can use SQL INSERT. Note that these are all seperate statements.
INSERT INTO LIAMALLAN1/CUSTOMERS VALUES( 1, 10.25, 'Liam Barry', '[email protected]' ) INSERT INTO LIAMALLAN1/CUSTOMERS VALUES( 2, 100.66, 'Eric Jooka', '[email protected]' ) INSERT INTO LIAMALLAN1/CUSTOMERS VALUES( 3, 1123124.12, 'Emily Bae', '[email protected]' )
How do I really start using it?
Now we have some data, we can really start using Embedded SQL. So, make sure you have a test source member/steamfile to put your Embedded SQL in. Embedded SQL allows any regular DB2 statement within your source, be it DELETE, UPDATE, INSERT or SELECT.
As SELECT may be the most important one for beginners, we'll look at that first. As good practice, for every PF I use within Embedded SQL, I like to declare a data-structure (Dcl-DS) matching the PF fields. I also make it a template, incase I want to use it in multiple places.
//Template data structure matching CUSTOMERS file Dcl-DS CUSTOMER_Temp Qualified Template; CUS_ID Int(10); CUS_BAL Packed(11:2); CUS_NAME Char(25); CUS_EMAIL Char(50); End-Ds; Dcl-DS CUSTOMER LikeDS(CUSTOMER_Temp);
Selecting one record from the file is a simple start, and useful if you're writing something like a maintainance screen.
Exec SQL SELECT CUS_BAL, CUS_NAME INTO :Customer.CUS_BAL, :Customer.CUS_NAME FROM CUSTOMERS WHERE CUS_ID = 1;
And as you can see, it's simple to get data - very easy. What if we update data on our maintainance screen? The next snippet of code sits below the previous SELECT statement that we created in our RPG.
//Imagine this is the change on our screen Customer.CUS_NAME = 'Barry James'; Exec SQL UPDATE CUSTOMERS SET CUS_BAL = :Customer.CUS_BAL, CUS_NAME = :Customer.CUS_NAME WHERE CUS_ID = 1;
After we have compiled and ran this program, open STRSQL and SELECT * FROM CUSTOMERS..
Lots of data
It's a need to SELECT more than one row at a time, luckily you can do this with cursors. Note, when using cursors: make sure you close the cursor when you've finished using it - you're causing yourself problems if you don't do this. Luckily, we declared our CUSTOMER data-structure so we can re-use it in our do-while.
You delcare your cursor with your SELECT statement. The syntax is a bit like EXEC SQL DECLARE [cursor-name] CURSOR FOR [select-statement].
Exec SQL Declare Cust_Cur Cursor FOR SELECT * FROM CUSTOMERS;
Even after we've closed the cursor, we are able to re-open it again - but not while it's already open. I've commented on the code instead of seperating it into blocks.
Exec SQL Declare Cust_Cur Cursor FOR SELECT * FROM CUSTOMERS; //Open our cursor that we defined previously. Exec SQL Open Cust_Cur; //'00000' = Unqualified Successful Completion If (SQLSTATE = '00000'); //Attemping to get the first record from //CUSTOMERS into our CUSTOMER data structure. Exec SQL Fetch Cust_Cur Into :CUSTOMER; //'00000' = Unqualified Successful Completion Dow (SQLSTATE = '00000'); //Print some data printf(%Trim(Customer.CUS_NAME) + ': ' + %Char(Customer.CUS_BAL) + x'25'); //Fetch the next record Exec SQL Fetch Cust_Cur Into :CUSTOMER; ENDDO; ENDIF; //Close the cursor.. WE MUST CLOSE THE CURSOR Exec SQL Close Cust_Cur;
This code will loop through each record in the CUSTOMERS file and print some relevant data out. It looks something like this..
Deleting data
There is still a lot of cursors I haven't covered.. but this is a good start. The last part I will cover is deleting data from the CUSTOMERS file. It's simple, like all over Embedded SQL statements EXEC SQL [statement]. There are two ways I'm going to show. The first is a hardcoded CUS_ID, the second is using Customer.CUS_ID.
Exec SQL DELETE FROM CUSTOMERS WHERE CUS_ID = 1;
Customer.CUS_ID = 2; Exec SQL DELETE FROM CUSTOMERS WHERE CUS_ID = :Customer.CUS_ID;
The ending result would remove two records from the file.
4 notes Ā· View notes
worksofbarry Ā· 8 years
Text
COMMON 16
I am just starting my 4th day at COMMON and I can just say I've had an amazing time - I actually sat it the breakfast breifing as I write this.
Day 1 - Saturday
I'd awoke very early this day, it probably didn't help that I was excited. Either way, I was ready to go out by 7, so I left my room and went to the cafe in the hotel and just sat around. The feeling of being in the US was still new to me and it made me very excited.
Shortly after I'd realised where I can collect my COMMON badge, which also includes a free t-shirt and bag. I love the bag, it's my new favourite thing and for some reason I am excited to wear it to work.
Then I started to meet the Club-Seiden bunch. Steph (@jordiwes) actually caught me on an escalator as I was heading back to my room - I procecced to meet her in a few minutes - which led me into meeting Chuk (@ChukShirley) and Alan (@alanseiden). Alan is a very pieceful guy and I feel as if I put the time in, I could learn a lot from him - not just about development, but about mine and others well-being.
We all left as a group for lunch in NOLA and I had some of the best tasting bread in my life - it was fabulous, one of a kind + the bacon is good too = bacon roll! Then we procecced to a cemetery tour in NOLA. Although it was very hot, I had a great time and learned a lot of history - at the time of writing this I have forgotten all of it.
Then, on the way to the pool I met Trevor (@ericjooka). Trevor is one heck of a guy, very inspiring. A lot of the trip has made me look at how my work life balance is. Currently, my work is on IBM i and my life is 50% on IBM i (the other half is on my girlfriend). He made me think what I actually want from my life and where I want my career to head.
I started to meet more and more CS members because then I met Dave (@PHPDave). He looked and sounded totally different from what I imagined, he's also a great guy. I mainly have to thank him for getting me into Club-Seiden, which leads me into thanking Alan for creating it and then follows on to thanking King Harrion (@kingharrison) for bringing Trevor in because he was the one that got me to COMMON really + a lot more.
Trevor invited me out for dinner that night - and who turns down dinner, not me! I had a lovely time, I met people that are important to him and it was really nice to see.
Day 2 - Sunday
This day was the real start to the event. I'd met lots of people and sadly I'd forgotten their names within minutes - but lucky I have their business card so we can keep in touch, which I planned to with anyone who gave me their card. I had to collect my award on stage and at this time I also met Kody (@BKodyRobinson), the Innvovation Award winner.
I had to present this day and the room was fairly packed, it even had some of the CS gang in + Steve Will of IBM (@Steve_Will_IBMi). I got some great feedback from the attendees and they seemed very interested with the the demo of the package manager and the Project Alexis debugger.
Then came the expo/booths; everyone was lovely and I met a lot of IBM people who work on the IBM i OS + the features of it. Infact, I met so many people I couldn't put a number on it; but most importantly I'd like to thank Elizabeth Hudson from IBM marketing (@itselizabeth_h) for keeping me company as I strolling in circles around the booths.
Key moments
This section going to cover more key moments, I'm writing this on day 5 so I can only highlight the topics.
I cannot stress enough how important the Club-Seiden bunch are to me. All of them are lovely and this trip wouldn't have been as good if I didn't know them. If you're reading this guys, thank you all so much for an amazing time. It's not likely I'm gonna see you again anytime soon, but I hope we cross paths again.
I'd like to thank both Elizabeth and Kody for coming out to dinner with me (or taking me out, whatever you prefer). It was nice to know what your interests are and what you do in your jobs + we even talked about our country's politics.
Trevor Perry is a great man. He's so open and he has really made me look at how I want to live my life. He got me 4 free books (expensive ones..) and he introduced me to some amazing people too, like Steve Will and Jim Buck + more.
The IBM i open-source round table on Tuesday night was very intersting - at the start, the points were mostly focused on open-source on PASE. I brought up the topic of open-source on the ILE and it caused a lot of discussion - and a lot came out of it.
End
Like I said, I had an amazing time. I can't stress how grateful I am to Trevor and Club-Seiden. All these people are so smart and I have a lot to learn from them. Thank you COMMON and NOLA for a wonderful time, I will miss it.
8 notes Ā· View notes
worksofbarry Ā· 8 years
Text
TOP language (IBM i) - object orientated?
TOP has a new feature which I like to call 'call virtual' - which 'emulate' an object orientated feel in your program - below is the snippet from the documentation. I will be honest, these aren't the best examples - but I couldn't come up with anything better.
Call virtual
There is a very useful feature that may allow your program to act more object orientated. You are able to invoke a function through an object, we call this 'Call virtual' function.
callvirt PersonObj->setName("Barry") name = [virt PersonObj->getName()]
These 'call virtual' features introduce two new keywords, callvirt and virt. callvirt is used as a statement and virt is used as a keyword in an expression. For example, if you had a setter, you'd use the callvirt because no data would come out of it. If you had a getter, you'd use virt within an expression to get the data out - like in the example above.
You must declare your 'virtual functions' as regular functions, from there they can be invoked. For example, here's a setter for setName:
function setName parameters(Name) this->Name = Name return *WORKING end
To reference back to the object you're invoking from, you use the this variable which is defined for you when you invoke the function from a 'virtual call'. You're able to access all object's fields using the this variable.
Here's an example of getName (the getter):
function getName return this->Name end
'Call virtual' should be used to contain object specific business logic. For example, if I had an Account object with two fields of Name and Balance I could create have function called addBalance which might look something like this:
function addMoney parameter(Amount) this->Balance = [dec this->Balance + Amount] end
If I wanted another function to remove an amount, but not let my balance go under 0.00; it may look something like this:
function removeMoney parameter(Amount) this->Balance = [dec this->Balance - Amount] if(this->Balance < 0) this->Balance = 0 end end
If it was a requirement to get double the amount the Customer object would have, with some kind of validation; it would look like this:
function getDoubleAmount var doubAmount = [this->Balance * 2] ## with a maximum of 1000 if(doubAmount > 1000) doubAmount = 1000 end return doubAmount end
You could invoke these functions like so:
callvirt CustObj->addMoney(100) printf(CustObj->Balance) printf(virt CustObj->getDoubleAmount()) callvirt CustObj->removeMoney(110) printf(CustObj->Balance)
1 note Ā· View note
worksofbarry Ā· 8 years
Text
TOP Language optimiser
Last night, I started to create an instruction optimiser for the TOP compiler - the idea is that it'll reduce the instruction count at compile time. This post is a little bit about it!
In the Project Alexis VM, the most runtime-heavy operations are adding static values to the stack (not variables or objects). For example, this code snippet is adding two constants together.
.LDVAL 5 .LDVAL 5 INTADD .STLOC number
This code takes time, just to add static data.. it's a joke! The compiler will now process these calculations at compile time. The above snippet now looks like this:
.LDVAL 10 .STLOC number
It can also do the same for CEQ.
.LDVAL Some`string .LDVAL Some`string CEQ
In theory, would become:
.LDVAL 1
This optimiser is the next step to making TOP a fast language - the next step in the optimiser what I call 'use-checking'. It will scan your instruction set, and if it finds variables that are declared but not used: it will optimise for you!
2 notes Ā· View notes
worksofbarry Ā· 8 years
Text
Travelling for IBM i!!
So, a lot seems to be happening in my life right now. Hereā€™s a section for each piece!
Firstly, there are lots of people I must thank for all these wonderful opportunities. Most of these events are somewhat life changing for me and the outcome of them can only get better. If youā€™ve helped me get to these places (you know who you are!!), then I canā€™t thank you enough.
COMMON 16 (US)
Iā€™m going to COMMON and I know I made a post about this already, but itā€™s tough to contain the excitement. Iā€™ll be doing two presentations, the first on the TOP programming language and the Project Alexis Virtual Machine; the second titled ā€œI tried creating an RPGLE compiler for .NET (and failed..)ā€ at one of Trevor Perryā€™s ReCon sessions.
You can find the Sched page for my presentation here!
If you donā€™t know what TOP is, (I made some posts about it previously) itā€™s a programming language for IBM i that runs on the Project Alexis Virtual Machine - but the key thing is that they are both written in RPG. Even though Iā€™ve never written in Python, the language is probably most likely comparable to that - you can see some syntax exmaples in this previous post. The virtual machine was inspired by .NET, and if youā€™re coming to the presentation youā€™ll find out how - you can read more on the inner workings of the VM here.
The second presentation is about an compiler I started for .NET, called RPGNet, which allows you to write RPG code and then compile it under the .NET framework. It was an amazing project, so much fun to work on and even open-source (not something you see in the RPG community sadly). The reason it ā€˜failedā€™ is because I stopped working on it. I didnā€™t have enough time to work on it as much as I wanted really, but only yesterday I implemented RPG data structures and it reminded me how much fun it was! You can see my messy code for RPGNet here.
I finally get to meet some of the members from Club-Seiden, these guys mean a lot to me - itā€™s them who really got me to COMMON. Hopefully Iā€™ll get some selfies or a group shot with the team!
COMMON EUROPE CONGRESS 16 (Sweden)
Iā€™ll be attending CEC 16 this year also! I am not sure if I will be presenting - but hopefully I will! Iā€™ll post more when I know more myself. If I am to present, itā€™ll be on TOP and Project Alexis (probably).
Summary
To sum it up, I am still in shock to even have these things to ever occur in my life. To finish off, hereā€™s the TOP logo which my girlfriend made..
Tumblr media
7 notes Ā· View notes
worksofbarry Ā· 8 years
Text
2016 Annual Meeting and Exposition trip!!
I somehow won a trip to America to go to the COMMON 2016 Annual Meeting and Exposition in New Orleans, Louisiana on May 15th. I travel out on the 13th from Heathrow and return on the 19th.
There are lots of people I cannot wait to meet, lots of inspirational people in one big place is just going to be amazing to me.
If you hadn't seen the blog posts about the programming language and virtual machine - I submitted that one large project and I got chosen which is just amazing. This is such a big moment in my life, things just couldn't be better.
I am due to present these projects at COMMON, hopefully I can get a recording of the presentations to post on the blog.
My girlfriend and I went out to celebrate at Turtle Bay for lunch, and we're currently ordering Dominos for dinner. xxxxxx
I am a very excited Barry!!
3 notes Ā· View notes
worksofbarry Ā· 8 years
Text
TOP Language for IBMi
I can confirm that from today, the language is in a very good state. Parser is good, virtual machine is good, lots of features and still lots more to come.
Just this morning I had to re-write a lot of the dynamic SQL functionality just to add the SQL.structureM function - but it was worth it because it allows the language to be more dynamic when using SQL:
var cmd cmd = "DSPOBJD OBJ(PALANGCMP/*ALL) OBJTYPE(*ALL) " cmd .= "OUTPUT(*OUTFILE) OUTFILE(QTEMP/STUFFS)" QCMDEXEC(cmd) POP() SQL.load(QTEMP, STUFFS) SQL.structure(QSYS, QADSPOBJ) if(SQL.open() == 1) while(SQL.read() == 1) printf(SQL.get(ODOBNM)) end end
Another great thing is that you can now use WEB. functions to send requests+get response and download files now. Here's an exmaple:
var webresp WEB.send("https://api.bitcoinaverage.com/ticker/EUR/", 1000) printf("Web response length: " . WEB.length()) printf("First 100 characters: ") webresp = WEB.get(1, 100) printf(webresp)
In this example, it sends a request off to the URL specified and returns the first 1000 characters. It then prints the length and the first 100 characters of the response. I would post a better example, but it's still a work in progress at the moment.
I'm just trying to say that it's coming along well, and the documentation for it is on always being updated as I may any change at all - and is usually reviewed by someone.
5 notes Ā· View notes
worksofbarry Ā· 8 years
Text
IBMi Language implementation
I think this may be the first time I've hesitated writing a blog post about a project. I'd already made 2(?) videos of the virtual machine and a 20 minute video of the language on top of it - but now a blog post.
For the last 3/4ish weeks I've been writing a virtual machine and a programming language on top of it for IBMi systems. I stopped working on the virtual machine about a week ago and spent my week off work implementing the language on-top of the virtual machine.
It took me 2 days to get the compiler working in a decent state with some fun features. The day that become a working program was my birthday - I spent the rest of the week making fixes and also improving the virtual machine.
Language features would include
Variables + arrays
Objects
Functions + plently of built-in functions
Implicit types
Physical file access
Easy syntax (sadly not the prettiest)
I'm going to talk about the two best features: Functions and Objects. Functions are great. It's very simple to delcare function parameters and you do not need to specifiy if the function returns a value or not. It's so dynamic, it makes it so the programmer doesn't have to worry very much.
function displayText parameters(textValue) printf(textValue) return textValue end
Objects are my all time favourite. An object can contain fields, for example, you could have a person object:
obj Person Name Age end
Then you can write code to create new instances of this person and change it's fields:
var PersonObj PersonObj = new Person PersonObj->Name = "Barry" printf(PersonObj->Name)
It's not far into development really, but it's so dynamic that it doesn't take long to implement new features. One problem I am having is naming the language. The only idea I have in mind is 'Top', because the extention I've been giving the source members is 'TOP' (because it sits on-top of the virtual machine).
1 note Ā· View note