Back to basics II
November 30th, 2007It’s been a while since I posted. Big project. Boring stuff. ‘Nuff said!
Anyway, a coworker asked me a question which I’ll now pose to you o’ ferocious reader:
How do you print the *sysopr message queue?
It’s one of those questions that comes out of left field and then bothers you if you don’t know. I looked for a function key from within DSPMSG and found none. I considered message reading all of the messages in a loop and writing them to a spoolfile. Duh, that’s how you view Data-queues. Know the answer?
Type in DSPMSG and prompt it. Yeah, the most obvious answer is right in the initial parameters and the OUTPUT keyword.
DSPMSG MSGQ(*SYSOPR) OUTPUT(*PRTWRAP)
You can use *PRINT or *PRTWRAP as the option but I think the linewrapping option makes it easier to read.
Anyway, back to basics I go yet again. After doing this for years you get a feel for how to do things and sometimes you can’t always trust your virtual sense of touch. As you upgrade the machine & new versions come and go so do parameters, function keys & options. From now on, at least once a year, I’m going to re-school myself by reading the help text on commands to make sure IBM didn’t add a new helpful tool somewhere along the way that I failed to notice in the change logs. If I don’t I might one day be that developer that just today asked me “What’s LE?” when I told him that I store my source in QRPGLESRC. If you’re not careful IBM will leave you behind while they move on to bigger/better/shinier things.
Until next time: Never stop learning!
Fear of Commitment
September 25th, 2007We have a data queue monitoring program that runs pretty much all of the time. Last week we decided it needed to log what it was doing. The first time we fired it up & ran some transactions through it I immediately glanced at the log to make sure it was working and … the log was blank. Whoops! I killed the job and was about to start debugging when I realized what was going on. I looked at the log file again and the records were there.
What’s going on: The AS400 is clever enough that it knows writing one record at a time to a file is wasteful. It normally waits until it has a bunch of changes to make before allocating the file and doing its thing. This speeds up processing, causes less wear on hard drives, etc. So, when I’m looking at the log while the job is running the records might not have actually been written permanently to the drive.
How do I stop this insanity?Don’t. It’s a good thing! Just be aware that it’s there and working for you! If it does happen that you need to turn it off you can use CHGPF to change the blocks of writes/updates/deletes that the AS400 will keep in memory before forcing them to be written to the file. Here’s the command:
CHGPF FILE(myfile) FRCRATIO(1)
This effectively forces a write with every operation stored in memory. You can also specify this when you compile the file if you’d rather go route.
Until next time, force your mind to write this knowledge into your auxiliary storage!
More fun with dates - %Diff
August 23rd, 2007We have a few antidiluvian date convert programs that still get called from time to time. They’re of the ‘Convert 6 digit date to julian’ variety and since the system was made Y2K friendly back in late November of 1999 they’ve mostly been unnecessary.
Until today.
Looking for a quick programming solution to get the duration between two dates in an older RPG 3 program one of our proggies reached for CUT009X - a CL that actually calls a duration calculator from the TAA tools repository. It works as it should except if the from-date is greater than the to-date. No negative durations allowed!
Since we needed all possible durations we needed a 21st century solution and as always, IBM has an answer. The %Diff function has been around for a while now so I won’t call it a hidden feature I’ll just call it and be done.
From = d’20070101′
To = d’20071231′
duration = %DIFF(To:From:*Days)
duration is set to 365. To easily replace all of the programs calling the old CUT009X program I’d wrap the parameters (numeric 8,0) in a %DATE() function.
dur = %DIFF(%Date(To:*ISO):%Date(From:*ISO):*Days)
Works beautifully with positive or negative durations. I’m excited. What can I say? I like nesting built in functions!
Until %time(Next)!
CPYF INCREL doesn’t work like you think.
August 1st, 2007Found a funny little bug today.
CPYF … INCREL((*IF REFKEY *GT ‘TER’) (*AND REFKEY *LT ‘TES’))
You’d expect this to copy the records where REFKEY begins with “TER” but it actually copies nothing. Query/SQL correctly matches the records, but not CPYF. Oddly enough, if you change the greater than (GT) to greater than equal (GE) and LT to LE it finds & copies the records just fine.
The other work around is to fully document the fields for comparison. If REFKEY is 10A, try it thusly and it works:
INCREL((*IF REFKEY *GE ‘TER ‘) (*AND REFKEY *LE ‘TES ‘))
In fact, just adding one space after the ‘TER ‘ / ‘TES ‘ seems to do the trick. Why this should be is a mystery to me. Until someone explains it, I’ll call it a bug. Thanks for reading!
Remote DB Administration
July 20th, 2007Today’s fun info is brought to you by the letters D R D & A! DRDA stands for “Distributed Relational Database Architecture” and makes it possible to access files on remote AS400s or logical partitions. We’ll be using interactive SQL to perform this magic with just a bit of pre-magic setup.
First, you’ll have to have what I like to think of as a network short cut to the remote AS400’s relational database. Sign onto the remote box and type WRKRDBDIRE. You should see the name of your remote machine’s DB defined as type *LOCAL. Make note of the name of the *LOCAL DB. Mine called itself S109D4CD. Sign onto your local AS400 and again execute WRKRDBDIRE. Type a 1 and the remote boxes RDB name into the appropriate line and press enter. Change the alias to be something you’ll remember (I used DEV), the Remote Location to your remote 400’s IP Address and the Type to *IP. Press enter to create the link. Alternately you can skip the menu and run this command filling in your specifics:
ADDRDBDIRE RDB(DEV) RMTLOCNAME(192.168.100.100 *IP) TEXT(’Development box’)
With the setup done, we can jump into STRSQL and connect to the remote box!
CONNECT TO dev USER edalton USING ‘password’
Yes you need the quotes around the password and yes, you have to type it visibly onto the screen. It vanishes after you hit enter though so it’s not as bad as I initially thought it would be. Anyway, you’re now connected to the remote database. Any selects/updates/inserts will be operating on the remote system. When you are done, type the DISCONNECT command to leave the remote DB.
There you have the quick/dirty primer to DRDA sql connections. Stop by at a later date when I attempt to embed this stuff into SQLRPGLE! Until next time, this has been TM Ericles.
I’ve got 50 ways…
July 10th, 2007Sometimes we forget that CL programs aren’t as refined as RPGLE programs. I was just burned on this fine point over the Month End when a new utility was added to a few dozen CL programs. In a nutshell, each of these CLs calls an external program to write one record to a log regarding the report that was just submitted. At the last minute I added the functionality to include a string of text (50A) that would serve to override the program description if not blanks.
Well, I passed ‘ ‘ for the parameter 99% of the time. The trouble is in RPGLE if you pass *Blanks for a parameter the program is smart enough to pass 50 blanks. CL is more litteral and it goes back to programming 101 - don’t pass 1 character when the receiving program expects 50! The result is that sometimes the string was blanks and sometimes it was random garbage from memory making a mockery of my loggery.
In retrospect I could have made it easier on myself by making the last parm optional but now I either have to go back and fix dozens of programs (which contain on the average 4 calls to the subroutine) or modify the receiver to check only the first digit. I chose the latter of course because time is money and cludge that works is better than a useless log.
Until next time, document that cludge!
Array for Pointers!
June 15th, 2007Back in the dark ages (V4R5) if we wanted to use several identical fields in a file like an array we had to do some fancy overlays of datastructures & hard code the field names.
No longer! Imagine you have a file with 9 fields STBOX1 through STBOX9 all defined the same. This snippet is functionally unreadable but I like it.
d boxes s like(STBOX1) dim(9) based(boxPtr)
d boxPtr s * inz(%addr(STBOX1))
This defines an array called BOXES with 9 elements sized like STBOX1 and beginning at the position in memory where boxPointer begins. boxPtr is then defined to begin where STBOX1 begins.
Diagram: boxes(1-9) = boxPtr = STBOX1-STBOX9
The end result is you can change Boxes(1) and you’ll be actually changing STBOX1. Need a total of all 9 fields in the file? %xfoot(boxes).
Easy enough! Please be careful with the above code. Remember, without good comments and documentation, it’s not polite to pointer!
-TM Ericles
Back in my day our files were flat!
June 6th, 2007Yes, back in the days of a flat earth the files were flat too. A “flat” file is so named because, like a flat piece of paper, it doesn’t contain any of the niceties of a file in a relational database. No history lesson here; I’ll just say that modern database files make life easier on the programmer!
Every once in a while we’ll have to still have to work with a flat file however. The file may come from a vendor by FTP or from the 400 itself by exporting a command to file but invariably the file name = the format name = the single field name and any standard RPG compiler will have a fit. There is a work around, though in this case it’s just the really old way of doing things. For this reason I’m tagging this entry as a “hidden feature” just because we all happily forgot how to do this as soon as humanly possible.
To cover the bases we’ll be using two flat files - we’ll pull records from one and write to the other. Ready? Lets Internally Describe some files!
First, the F-specs. Note the lack of “k”, indicating a keyed file and the “f” instead of the “e” for external descriptions.
Fflatin ip f 132 disk Fflatout o a f 64 disk
Next we’ll need some I-specs to define the input file. You can break the file up any way you choose which is good.
Iflatin aa 01 I 1 10 id_field I 20 70 entry_field I 90 100 date_field
You can use any two characters you want for the ‘aa’ above. It’s just to keep multiple files separate. the 01 means the program will turn on *IN01 when reading from this file. Useful if you have multiple files being brought in Input Primary.
Next we’ll work with the fields in the same manor you would anywhere else.
c if id_field = 'WRKREGINF' c eval out_date = date_field c eval out_entry = entry_field c except OutIt
Finally, here’s the output specs we use. It’s all one exception and pretty basic.
oflatout eadd OutIt o out_date 10 o 12 '-' o out_entry 63
There you have it. Now I have this documented for the next time I run across this situation and don’t remember where to look to dup my old code. I’ll cover internally described keys another day but for now… it’s lunch time and I need to internally describe a hot pocket.
Reorg - Whenever!
June 1st, 2007Quick one today: RGZPFM
Reorganization of a physical file member requires exclusive access, right? Not any more it doesn’t! If you’re up to V5R3 you can forget about scheduling jobs to reorg files in the middle of the night, just specify LOCK(*SHRUPD) and let her fly.
Like defragging a hard disk, it’ll skip anything that’s in use. Also like a defreg, you can restart the reorganize right where you left off if you also specify ALWCANCEL (*YES).
I wonder where else Concurrent Access has been implemented… stay tuned!