You are on page 1of 22

Tips for Programming and Development, Part 1

Posted December 1st, 2007 in

By: NO AUTHOR

o o o

RPG Programming Application Development Database/SQL

APIs
Retrieve a Procedure Name Do you have to retrieve the name of a Click here to download the code bundle. current procedure? Often you need this To report code errors, email SystemiNetwork.com information as part of an audit or errorhandling process. There are two ways to get this information. Classic method. Send a message to the caller using the Send Program Message (QMHSNDPM) API, retrieve the message using the Retrieve Program Message (QMHRCVPM) API, and retrieve the sending procedure name. This method works fine but isn't great for performance. Additionally, some of the information isn't readily available. Better method. Call the Retrieve Call Stack (QWVRCSTK) API. This method also works fine, but users tend to embed the call to QWVRCSTK directly in the procedure (or in a copybook), which results in duplicated code. The solution is to have a single procedure called GetProcName() in a module called PROCNAME in a service program (also called PROCNAME). The PROCNAME *SRVPGM is in a utility binding directory called UTILITY, which all applications reference during compilation with the BNDDIR parameter to commands, such as Create Bound RPG Program (CRTBNDRPG) and Create Cobol Module (CRTCBLMOD). By including the PROCNAME_P copybook in your programs, you gain access to the GetProcName() procedure. When you need to know the name of the current procedure, simply call GetProcName, which passes qproc (a data structure also defined in the PROCNAME_P copybook). After the call to GetProcName, the qproc data structure contains the names of the library, program (or service program), module, and procedure that called GetProcName(). I like to use this approach in conjunction with the DUMP opcode to identify the QPPGMDMP program dump spooled file: /free D string ... ... procedure code here S 132A

... begsr *pssr; GetProcName( qproc ); string = %trim( qproc.library ) + '/' + %trim( qproc.program ) + '/' + %trim( qproc.module ) + '/' + %trim( qproc.proc ); dump(a) string; endsr; /end-free As a result, the top line of the QPPGMDMP spooled file has something similar to MYLIB/MYSRVPGM/MYMOD1/GetSystemValue where GetSystemValue() is the procedure that called GetProcName(). This information makes it much easier to find the correct spooled file if you have a lot of them. If you don't specify a parameter for the DUMP opcode, the top line of the QPPGMDMP spooled file simply says ILE RPG/400 FORMATTED DUMP. To download the code, go to SystemiNetwork.com/code. The code for the PROCNAME procedure and the PROCNAME_P copybook is included, as well as the code for a program called TESTPROCR that shows how to call PROCNAME. For more information about the compile preprocessor, read "Using a Compile Preprocessor" (August 2006, article ID 20611 at SystemiNetwork.com). Rory Hewitt Software developer San Francisco, CA Formatted Job Log Output Most of my web development has been on the .NET side of the fence. Typically .NET developers use the trace.warn() or trace.write() methods to output debugging information. However, when tracing CGI programs, I found no clean, low-overhead way of doing this until Bob Cozzi introduced me to an API. He uses the Qp0zLprintf API to send information to the job log. The RPG IV prototype Qp0zLprintf (Figure 1) might look a little odd because it really is a C function, but it's easy to use. The API expects at least one parameter as a string with a new line character (x'25') and null termination (x'00'). The options(*string) appends the null terminator; however, you must support the new character. If multiple parameters are passed to the API, the first parameter serves as the formatting string.

All other Qp0zLprintf functionality is identical to how you use the printf C function. The examples in Figure 2 both produce the same one-line entry in the job log. Message details similar to Figure 3 appear in the job log. From the time I was first introduced to this API, I have used it for more than debugging CGI programs. This API works well in long-running SQL batch jobs that require multiple statements to complete, when the API is incorporated in complex interactive programs used to determine business rules, or when the API is embedded into never-ending server job. Regardless of the way it is used, Qp0zLprintf gives developers a low-overhead, unobtrusive tracing tool for just about any kind of System i task. Eddie Alexander Information systems Levy Home Entertainment Retrieve DTAQ Maximum Length I have been frustrated with the lack of documentation (specifically about the maximum length of data that the DTAQ is set up to handle) when I need to send/receive data to/from a DTAQ. A quick way to find this value is to run the following command at the command line: CALL QSNDDTAQ PARM('MY_DTAQ' 'MY_LIBRARY' X'00000F' ' ') The four parameters in the preceding command represent DTAQ name (10 alpha), DTAQ library (10 alpha), DTAQ length (5,0 numeric), and DTAQ data (variable alpha value). Passing an invalid length in the third parameter (X'00000F' = value 0) causes the call to the API to display error message CPF2498: "Invalid length. MAXLEN for data queue MY_DTAQ in MY_LIBRARY is NNNNN," where NNNNN is the numeric value representing the maximum length the DTAQ can handle. You can use that value in an RPG program to declare the length of the fourth parameter passed to the API and/or to check for the string length passed to a DTAQ and avoid loss of data. To obtain the maximum data length for a DDM-type data queue, run the preceding command against the data queue on the remote system that the DDM data queue points to. Another way to retrieve the length (or key) attribute of an existing data queue is to call the Retrieve Data Queue Description (QMHQRDQD) API. The QMHQRDQD API returns information about all data queue attributes. This approach, of course, involves programming efforts and is therefore not a quick solution. Pepe Hiplito CEO Better RPG, LLC

COMMANDS
Yes, Yes, I've Tried It. Enough Already!

"Have you tried the modern alternative to PDM?" IBM asks you this question, albeit unobtrusively at the bottom of the screen, every time you use PDM. The second-level text of the message is a plug for its WDSc product. You can disable the message in your PDM session by changing your PDM defaults (press F18 when inside PDM) and saying "no" to "Display informational messages." Although turning the message off can be a relief, you can also use the message to serve your needs. In my shop, I use the message to pass bits of noncritical information to my staff, such as reminders to fill out TPS reports (obligatory "Office Space" movie reference). Use the following command to find and change the message text: WRKMSGD MSGID(PDM0760) MSGF(QPDA/QUOMSGF) Dan Darnell Independent consultant Little Rock, AR More Keys If you create a user interface manager (UIM) menu or panel, you need to create a key list to define the active and visible function keys. One optional key to always define is F24=More keys. :KEYI KEY=F24 HELP=morekeys ACTION='morekeys'. F24=More keys The morekeys action tells the UIM to cause function key 24 to be used if and only if insufficient room is available to display all the other function keys on the display lines reserved for function key descriptions. If sufficient room is available for all other function keys, F24 is not used for the panel or menu. One reason to use morekeys is to maximize the number of function keys displayed at a time. When morekeys is not used and function keys are conditioned, developers might be forced to create a truth table within the UIM source to tell the UIM compiler which function keys' conditions can be true together. The other option is to create panels that show fewer function keys than there are actually room for. Using morekeys for F24 is a much better solution. Ed Fishel Advisory software engineer IBM Rochester Never Accidentally Delete a Command Again If you use the System i command line, you probably use the Select Command (SLTCMD) command to find a command you are looking for. For example, SLTCMD WRKOB*

produces a list of all commands with names starting with the characters WRKOB. The list includes a short description of each command and lets you select your desired command. Unfortunately, the SLTCMD command name has just one character that's different from the Delete Command (DLTCMD) command, and the "D" character is just one position away from "S" on most keyboards. That means that some people have actually deleted commands they were trying to find and select. The solution is to key the partial command name followed by the asterisk on the command line. So instead of keying SLTCMD WRKOB*

key

WRKOB* to produce a list of commands with names starting with the characters WRKOB. Keying the partial command gives you two advantages. First, you have to key fewer characters, and second, there is no chance that you will accidentally delete a command. Ed Fishel Advisory software engineer IBM Rochester Universal Pop-up Command Line When I create an administrator user profile, I use the prompter for the Create User Profile (CRTUSRPRF) command, press F9=All parameters, scroll to the Attention program (ATNPGM) parameter, and specify the Display Command Line Window (QUSCMDLN) API. QUSCMDLN takes no parameters and displays a command line at the bottom of the current screen when called. This lets you get a command line any place the attention key is active. I think that QUSCMDLN is better than either QCMD or a menu for this purpose because it lets you see most of the current screen. This works well most of the time, but it does not let you use the attention key again until you exit from the command line produced by QUSCMDLN. To solve that problem, create the following simple program and use it as the attention program on your user profile. PGM SETATNPGM PGM(*CURRENT) CALL PGM(QUSCMDLN)

ENDPGM This program uses the Set Attention Program (SETATNPGM) command to set itself as the attention program at the current recursion level and then calls QUSCMDLN to display a pop-up command line. If you use this program, remember to back out of the pop-up command lines so that you do not use too many system resources. Ed Fishel Advisory software engineer IBM Rochester Execute a CL Command from an RPG Program There are three ways that you can execute a CL program from an RPGLE (or Cobol) program, and each has merit. Classic method. Use the Execute Command (QCMDEXC) API. This is probably the most common method found in RPG or Cobol applications, in part because it's been available to programmers since the beginning, when we were using RPG II programs. On the plus side, it's simple and easy to understand. On the minus side, getting error information back is almost impossible. C method. Use the system() API. This is the second-most common method. Available only to ILE programs, the C method is a little simpler to code than QCMDEXC, but again, retrieving error information is difficult except through the _EXCP_MSGID imported variable. Best way. Use the Process Commands (QCAPCMD) API. Like the two preceding methods, the QCAPCMD API lets you execute a command. However, it also lets you validate or prompt a command, returns the full command string (including keywords for positional parameters), and even lets you display command help text. It also includes the standard QUSEC API error parameter, which gives you more information about command errors. Consequently, this method is much more powerful than either QCMDEXC or system(). However, it's much more complex to code and is therefore used less frequently. Given that QCAPCMD is more powerful than the other two methods, using it makes sense, especially when retrieving command errors is important. However, if you are going to use QCAPCMD, you need a way to use it that doesn't require adding the more than 30 lines of code needed to call it. The solution is to have a single procedure called cl() in a service program that's put into a utility binding directory in QGPL, which is available to all programs. My cl() procedure is a wrapper to the QCAPCMD API. Because I have a lot of older calls to system(), I want cl() to have the same interface as system() a single command string passed as a pointer with the OPTIONS(*STRING) keyword and a four-byte (10I) integer return code, which returns 1 if an error occurs or 0 if the command completes successfully. This lets you replace system() calls with cl() calls. However, I also have a second (optional) parameter to cl() the QUSEC structure which is passed as an I/O parameter. If this second parameter is not passed, cl() calls system() and returns the return code. If the QUSEC parameter is passed, cl() calls QCAPCMD and returns the QUSEC value from that.

To download the code, go to SystemiNetwork.com/code. The code for the cl() procedure in the CMDPRC source member and the CMDPRC_P and QUSEC_T copybook is included, as well as the code for a program called TESTCMDPRC, which shows several examples of how you can call cl(). For more information about the compile preprocessor, read "Using a Compile Preprocessor" (August 2006, article ID 20611). Rory Hewitt Software developer San Francisco, CA Find a User Profile Without Using WRKUSRPRF If you are not authorized to use the Work with User Profiles (WRKUSRPRF) command, you can use the Work with Spooled Files (WRKSPLF) command to find a user profile. To do so, run WRKSPLF and press F21 to ensure that your assistance level is set to basic (1). You now see a prompt for the user at the top of the WRKSPLF panel. To get a list of users, position the cursor in the user field and press F4. Julian Monypenny System iNEWS technical editor

DATABASE
Database Access in QShell You may already be familiar with how to use the DB2 utility in QShell to execute SQL statements over your local database by entering DB2 "insert into custmast values(12345, 'DAN DARNELL')" or DB2 "select * from custmast" This utility is wonderful to have so that you can stay in QShell to perform data manipulation functions. The utility also lets you perform functions on a remote database great for anyone in a distributed environment. To use the utility with remote databases, specify a remote database name (-r rdbname), a remote user ID (-u userid), and a remote password (-p password) along with your SQL statement, as in the following example: DB2 -r CHICAGO -u DAN -p MYPWD "select * from custmast" Dan Darnell Independent consultant Little Rock, AR

DRDA/DDM Debug Data Area QRWOPTIONS Beginning with release V5R1, a data area is supported to make it much easier to collect Distributed Relational Database Architecture (DRDA) and Distributed Data Management (DDM) debug materials. The data area must be named QRWOPTIONS, and it must reside in library QGPL. All data entered must be in CCSID 37 or CCSID 500. You can perform the following tasks through the data area: spool job log before jobs are recycled

o o o o o

generate DSPJOB spooled file before jobs are recycled trace the DDM/DRDA jobs start debug for the DDM/DRDA jobs set a QAQQINI file library shadow debug options from AR job

Collection can be set for all users, one user profile, or one client TCP/IP address. The current IBM QRWOPTIONS data area documentation is in the Information Center at publib.boulder.ibm.com/infocenter/iseries/v5r4/topic/ddp/rbal1qrwoptions.htm. For the TRCJOB and STRTRC data area functions to be fully functional, you need to change the job description QGPL/QDFTSVR to specify that inquiry messages be replied to via the system reply list entries if possible. Otherwise, the requested trace may not print correctly. To change the job description, do the following: 1. On the operating system command line, type CHGJOBD JOBD(QGPL/QDFTSVR) INQMSGRPY(*SYSRPYL) and press the Enter key. 2. On the operating system command line, type ADDRPYLE SEQNBR(4072) MSGID(CPA4072) RPY(NOMAX) and press the Enter key. 3. Restart the prestart jobs.

When you are done tracing, remove the reply list entry from the user system when you remove the data area by following these steps: 1. On the operating system command line, type CHGJOBD JOBD(QGPL/QDFTSVR) INQMSGRPY(*RQD) and press the Enter key.

2.

On the operating system command line, type RMVRPYLE SEQNBR(4072) and press the Enter key.

3.

Restart the prestart jobs. Carsten Flensburg System iNEWS technical editor

Reposition the Cursor at theBeginning of a Subfile Usually, the cursor automatically repositions to the beginning of the subfile after all subfilechanged records are processed/read (by using READC) and the end of the subfile is reached. The changed records can then be processed again if the cursor associated with the keyword SFLNXTCHG is set *on/*off to mark the records as "changed," and the subfile records are updated. However, what happens if you have to stop processing changed records in the middle, before reaching the end of the subfile (e.g., because of bad data that the user entered)? If the program immediately tries to process the subfile again without rewriting the subfile control format, the next READC will not read the first changed record in the subfile, and it will keep going from wherever it stopped in the previous iteration. How can you get the program to start at the beginning of the subfile and read the changed records again? The trick is to reposition the subfile pointer before the first subfile record. The only way that I have found to accomplish this is to use the CHAIN opcode. By chaining to relative record number 0 which does not exist, hence the need to control the error the pointer resets to the beginning of the subfile before the first subfile record. See Figure 4 for a code example. Pepe Hiplito CEO Better RPG, LLC

DATA MANAGEMENT
Embedding Formulas in CSV Files Do you know that you can embed formulas in comma-separated value (CSV) files when you send data from your System i to Microsoft Excel? Excel evaluates each field or cell that you send it. As a result, you can send more than just text and numbers. You can send any formula that you can enter in the formula bar complete with cell references. Consider the following CSV file: 1,"00001234.25","x","=TEXT(B1,""$0.00"")" 2,"00002345","y","=UPPER(B2)"

3,"00001111","z","=RIGHT(""000000""&B3,6)" =SUM(A1:A3),"=SUM(B1:B3)","Sum","" =AVERAGE(A1:A3), "=AVERAGE(B1:B3)","Average","" Figure 5 shows how Excel evaluates this text file. Note that any quoted references in a CSV data file should be double-quoted so that Excel knows the quote mark is actually part of the cell being parsed. Also, I find it handy to have a service program with functions that you do repeatedly for CSV extraction. For example, Figure 6 shows a GetExcelCell procedure that converts a column and row number to the equivalent A1 cell reference style. This procedure should work fine for data with fewer than 256 columns and 65,536 rows (the limits for Excel 2003). Eddie Alexander Information systems Levy Home Entertainment Google It! Once in a while, you may need to convert numbers from one base to another, such as a decimal number to a hexadecimal. Many software programs can do the conversion for you, or maybe you've written your own program. All you really need to do, though, is use Google. Google's search entry is also a calculator that converts numbers from one base to another. Just enter the value and then the base in which you want the conversion (Figure 7). The following table shows some popular data conversions and the Google results.

Enter

Google Returns

0x15 in decimal 21

15 in hex

0xF

15 in octal

0o17

0x15 in octal

0o25

0o17 in decimal 15

Jef Sutherland System iNEWS technical editor

Hex in DSPPFM Many System i professionals now have data moving between different types of servers, operating systems, and character encoding (e.g., ASCII, EBCDIC). I still use one of the most rudimentary and long-lasting commands on the midrange platform to see character values in hex Display Physical File Member (DSPPFM). To view the hex values in a file, press F10 on the initial display for DSPPFM (Figure 8). For an over/underview, which I like better, press F11. You can see that the hex value for G is C7. Jef Sutherland System iNEWS technical editor Watch for Part 2 in an upcoming issue for tips on using Groovy, SQL, and WDSc.

Tips for Programming and Development, Part 2


Posted January 1st, 2008 in

By: Craig Caulfield By: Eddie Alexander By: Julian Monypenny By: Jef Sutherland By: Don Denoncourt By: Don Yantzi

o o o

RPG Programming Application Development Database/SQL

Groovy
Install the Groovy Eclipse Plug-in to WDSc 7.0 To install the Groovy Eclipse plug-in to WDSc, go to WDSc's application main menu and select Help|Software Updates|Find and Install. 1. In the Install/Update window, click Search For New Features|Next|New Remote Site button. 2. In the pop-up window enter: 1. Name: Groovy URL: http://dist.codehaus.org/groovy/distributions/update/

2.

3.

Check the new Groovy repository and press Finish.

4. Under "Select the Features to Install," select the Groovy check box (be sure to get the latest version) and click Next. 5. 6. 7. 8. Accept the agreement and click Next. If the default location looks okay, press Finish to download the plug-in. If you get a warning that the plug-in is unsigned, click Install or Install All. Restart WDSc.

Note: As of August 2007, the Groovy plug-in works with WDSc 7.0 but not 6.0. Don Denoncourt System iNEWS technical editor Create Your First Groovy Project To create a Groovy project, go to WDSc's application main menu and select File|New|Project| Java Project and click Next. If you get a pop-up window with the message "This kind of project is associated with the Java perspective," click Yes. In the New Java Project window 1. Enter the project name groovierjava.

2. In the Project Layout section of the window, click the "Create separate source and output folders" button. 3. Click Finish.

After the project is created, in the Package Explorer view, select the newly created project, right-click, and select Groovy|Add Groovy Nature. Then choose the newly created project, right-click, and select Properties|Build Path|Configure Build Path. Click the Source tab and then the Browse button next to the Default output folder input prompt. Finally, select the bingroovy directory, click OK, and then click OK again. Test Your Groovy Script Test your Groovy script in WDSc's Package Explorer view by expanding the groovierjava project node and selecting the folder labeled src. Right-click, select New|Other|General|File, and click Next. Enter the File name testscript.groovy and click Finish. The testscript.groovy file is automatically opened in the Groovy editor. Type the following in the groovy source file: println "Now I'm Groovin'" Save the change by clicking File|Save. To run the script, choose testscript.groovy in the Package Explorer view, right-click, and select Run As|Groovy. The output appears in the Console view at the bottom of WDSc.

Don Denoncourt System iNEWS technical editor Generate XML, Beans, Stored Procedures, and Views for Grails with Groovy In "The Search for the Holy Web Dev Grail(s)" (November 2007, article ID 21061 at SystemiNetwork.com), I introduced the Groovy programming language and the fantastic Grails web-application frameworks. Grails was influenced by Ruby on Rails but, unlike Rails, Grails supports legacy databases. But as I discussed in the article, Grails is not without problems. First, Grails works best when there is a single key field, whereas many legacy databases use composite keys. Second, the customization requires creating Hibernate XML mapping documents. In "Hibernate Your JDBC" (October 2007, article ID 21035), I proposed, as a solution to these problems, creating an SQL view (that adds the relative record number to the list of fields) and a stored procedure to handle insert operations. But writing the code for the view, stored procedure, Hibernate mapping XML, and the JavaBean or GroovyBeans is a timeconsuming and error-prone process. I have decided to "eat my own dog food" and use Groovy to generate the objects. I am amazed how easy it is to work with XML, SQL, and text files with Groovy. I wrote my Build400GrailsDomain Groovy utility in about a third of the time that it would have taken to write it in Java and with one-fourth the code. Groovy also provides my utility lots of value because it adds Grails constraints to the generated GroovyBean. GroovyBean constraints enable Grails' automatic validation. Figure 1 shows the Groovy script that uses the Build400GrailsDomain class in Figure 2 to build the Grails domain for the ALLTYPES file in Figure 3. Closures Let's look at how to implement the Build400GrailsDomain and check out some of the cooler features of Groovy. Perhaps the most compelling feature of a declarative language is closures. Closures are essentially blocks of code that are encapsulated as objects and, therefore, can be passed around. My utility uses this cool feature by having Build400GrailsDomain create GroovyBeans with attribute names constructed from the field column headings (or, if field column headings are unavailable, as in the case of ALLTYPES, Build400GrailsDomain uses the field name as the attribute name). To do that, Build400GrailsDomain has to remove underscores, camel-case the words, and replace nonalphabetic characters. I can't guess how you might want to use the tool to replace characters used in your file's column heading. I could have just told you to tweak Build400GrailsDomain for each file that you generate Grails domains on, but that would be tedious. Enter closures. The sample RunBuild400GrailsDomain script (Figure 1) shows a variable called nameManipulation, which is assigned a value that is a code block. The code block uses regular expressions to replace various characters (for more information about regular expressions, read "Search Source Code with Regular Expressions," August 2007, article ID 20981). The thing is, you might want to have different replacement options for various files. For example, the QIWS/QCUSTCDT file has the word "field" in every column heading, which is redundant. I replaced "field" with an empty string: attr.name = attr.name.replaceAll(/Field/, '') The closure called nameManipulation is passed to the Build400GrailsDomain's run method. The closure then passes to the retrieveTableAttributes method, where it is invoked with nameManipulation?.call(attr)

Let me take a moment to explain the question mark in that line. That's called a dereference operator. Groovy does not invoke the call method if the nameManipulation variable is null. I could have also used the more verbose Java syntax: if (nameManipulation != null) { nameManipulation.call(attr); } The cool thing about using a closure in my example is that you can use a different closure for each table. You can modify the behavior of the Build400GrailsDomain class without touching its code. Named Parameters Another Groovy feature that I use in the utility is named parameters. The Build400GrailsDomain has no constructor, but Groovy lets you pass name/value pairs to a constructor to clearly identify the class attributes you want to have set on the instantiation of an object (Figure 1). Writing XML Build400GrailsDomain's retrieveTableAttributes builds a list of TableAttribute objects (Figure 4). The list is named attrs and is used in the other methods of Build400GrailsDomain to create the view, stored procedure, domain class, and XML. The writeHibernateXML method implementation uses Groovy's MarkupBuilder (an example of a Domain Specific Language DSL). Look at the following statements in the Groovy source, then look at the generated XML in Figure 5. builder.'hibernate-mapping'() builder.'class'(name:domainName, ... id(name:'id', type:'int') { generator('class':'assigned') } property(name:attr.name, ... The method names and parameters in the Groovy code have a one-to-one relationship with the XML tags and attributes. Now, let me explain something: The methods really don't exist! Groovy uses its dynamic language capabilities to output XML with the tag and attribute names. Syntactic Sugar Before I finish, I want to highlight a few Groovy syntactical sugars: switch statements, loop constructs, and the Groovy String. I use Groovy's switch statements a lot. Most of the methods iterate over the array of TableAttributes and use a switch on the attribute type to create lines for the XML, domain class, or stored procedure. Had I implemented this in Java, I

would have had to use nested ifs, because Java's switch can handle only primitives such as integer, short, byte, or a single character. My Java classes are polluted with for loops, yet Build400GrailsDomain has nary a one. Instead, I used Groovy's each method. The each iterates through a list and passes each element to the closure (the statements between the curly brace following the each construct). The each method (as well as other similar methods, such as collect) simplifies the code required to process sets. Finally, I want to highlight my use of Groovy strings. The createStoredProcedure method defines a variable called storProc as a Groovy string that contains six lines of SQL stored procedure code. Groovy strings delineated with triple quotes can span multiple lines. Besides spanning lines, the string contains variable references delineated with dollar signs and curly braces, the values of which are replaced at runtime. You might also want to consider using the Groovy SQL classes because they greatly reduced the amount of JDBC you have to write. Don Denoncourt System iNEWS technical editor Groovy Generation of Grails Domain for Legacy System i Files Here's how to create a new Groovy/Java project as identified in the "Create Your First Groovy Project" tip:

1.

1. Copy RunBuild400GrailsDomain.groovy (Figure 1), Build400GrailsDomain.groovy (Figure 2), and TableAttributes.groovy (Figure 4) to the src folder of your Groovy project. 2. In the Package Explorer, select the project, right-click, and select Refresh.

3. The utility requires the IBM Java Toolbox for the AS400 so, if you don't already have the jt400.jar on your PC, perform the following: 1. I suggest using a Unix naming convention of opt (short for optional) for a directory that stores non-Windows registry programs and utilities. Open a DOS window, click Start, click Run. 2. Type CMD and enter the following script: 3. C:\>mkdir \opt\java\jt400 4. C:\>cd \opt\java\jt400 5. C:\opt\java\jt400>ftp [host name or ip] 6. ftp> cd /qibm/proddata/http/public/jt400/lib 7. ftp> bin 8. ftp> get jt400.jar

9. ftp> qui C:\opt\java\jt400>exit 4. In WDSc's Package Explorer view, select your Groovy project, right-click, and select Properties|Build Path|Configure Build Path. 5. 6. 7. Click the Libraries tab and click the Add External JARS button. Browse to C:\opt\java\jt400\jt400.jar and double-click jt400.jar. Back in the Java Build Path window, click OK.

8. Open the Groovy script called RunBuild400GrailsDomain.groovy by doubleclicking the file in the Package Explorer view. 9. Change the attribute settings on the Build400GrailsDomain line to point to your IP, user, password, library, file, and domain class name, and set verbose to true (if you want verbose output). 10. Save your changes.

11. In the Package Explorer view, right-click RunBuild400GrailsDomain.groovy and select Run As|Groovy. The GroovyBean and Hibernate XML are placed in the project's root directory, but the stored procedure and view are created in the library that you specified in the Build400GrailsDomain statement. Don Denoncourt System iNEWS technical editor

SQL
Query/400-like Row Numbers I really like that the Query/400 display shows the unique row number for each line when you run a Query/400 query. To do this with SQL, use the new OLAP features in V5R4. For example, to show the files on the system with line numbers, enter SELECT ROW_NUMBER() OVER() AS UniqueSeq, label, sys_tname, sys_dname FROM systables Though Query/400 can't restart at 1 for each new library, SQL can. Use the OLAP window function to specify the partitioning fields to apply to the row number: SELECT ROW_NUMBER() OVER

(PARTITION BY sys_dname) AS LibrarySeq, label, sys_tname, sys_dname FROM systables Lastly, with the following query, you can combine the prior two queries to get a unique row number along with the restarted sequence number by library:

SELECT ROW_NUMBER() OVER() AS UniqueSeq, ROW_NUMBER() OVER (PARTITION BY sys_dname)AS LibrarySeq, label, sys_tname, sys_dname FROM systables Eddie Alexander Information systems Levy Home Entertainment Improve Performance of Group By with a Join Whenever possible, limit column names on the Group By clause of a Select statement to columns in the first table in the From clause. Doing so might mean that you have to rearrange the statement. For example: SELECT MAX( H.CUSNAM ), D.ITEM, SUM( D.VALUE ) FROM ORDHDR H JOIN ORDDTL D ON H.ORDNO = D.ORDNO GROUP BY D.ITEM can run much faster if ORDDTL is specified first: SELECT MAX( H.CUSNAM ), D.ITEM, SUM( D.VALUE ) FROM ORDDTL D

JOIN ORDHDR H ON D.ORDNO = H.ORDNO GROUP BY D.ITEM Julian Monypenny System iNEWS technical editor Get the Right Totals on Many-to-Many Joins When you join two tables that have a many-to-many relationship, SQL joins all matching rows in the first table to all matching rows in the second table. To summarize values from both tables, specify a subselect on the join. For example, to total items' order and dispatch quantities, instead of SELECT O.ITEM, SUM(O.QTY), SUM(D.QTY) FROM MONYLIB.ORDDTL O JOIN MONYLIB.DSPDTL D ON O.ITEM = D.ITEM GROUP BY O.ITEM you should code: SELECT O.ITEM, SUM(O.QTY), MIN(D.DESPQTY)FROM ORDDTL O JOIN (SELECT ITEM, SUM(QTY) AS DESPQTY FROM DSPDTL GROUP BY ITEM) AS D ON O.ITEM = D.ITEM GROUP BY O.ITEM The subselect summates the dispatch quantity as DESPQTY and specifies a correlation name of D so that the values returned by the subquery can be referenced in the main query. The MIN function in the outer query ensures that DESPQTY is output only once for each item. Julian Monypenny System iNEWS technical editor

SQL's Case as a Pivot Table Excel pivot tables are a convenient way to count or sum both horizontally and vertically. I know people who use SQL (or another tool) to get data into Excel for the sole purpose of using the pivot table function. SQL, using the case keyword, can perform similar tasks. Because many people have the file QCUSTCDT in the QIWS library, I use it as an example. Assume that you need to find how many customers fall within a credit limit range (low, medium, max). You also want to group the results by the charge code field, chgcod (Figure 6). The SQL in Figure 7 uses the sum and case keywords to get the job done. Jef Sutherland System iNEWS technical editor Relative Record Number in SQL You can get the relative record number in a database using the SQL keyword RRN(filename). For example, the following code returns the list in Figure 8. select rrn(qcustcdt), cusnum, lstnam from qiws/qcustcdt Jef Sutherland System iNEWS technical editor

WDSc
Display Eclipse Workspace Location I like to keep my Eclipse and WebSphere Development Studio Client (WDSc) projects in separate workspaces so that my development environment doesn't become too cluttered. But this can occasionally be confusing, and I sometimes find myself wondering exactly what workspace I am using. Fortunately, Eclipse and WDSc can display the workspace path in the title bar. To display the path, start Eclipse or WDSc with the -showlocation option in the target field. Now, the full path of your workspace appears in the title bar so you always know exactly where you are. Craig Caulfield Senior development analyst Landmark Manage Eclipse Plug-ins Of all IDEs, Eclipse is probably the easiest to upgrade to a new version just unzip a fresh distribution and run the Eclipse executable. But after all your third-party plug-ins are installed to the default location within the installation directory, you need to download and configure the plug-ins again. A better approach is to separate your plug-ins from your installation

directory, which makes the update process simpler and, if you need to, even lets you share the same plug-ins across different Eclipse installations. Because WDSc is based on Eclipse, you can do the same with your System i development environment by following these steps: 1. 1. Create a directory somewhere outside the Eclipse installation directory (called, for example, eclipse-plugins) with the following directory structure:

o o o o

eclipse-plug-ins/ .eclipseextension + features/ + plugins/

2. The .eclipseextension file marks these directories as plug-in specific and should contain the following lines: id=org.eclipse.platform name=Eclipse Platform version=3.0.0 3. Use the version property to flag these plug-ins to a specific version. My previous entry works with any Eclipse versions after 3.0.0. 4. Next, you have to make Eclipse aware of the new plug-in location. To do this, use the Product Configuration dialog box in the Help|Software Updates| Manage Configuration menu.

5.

Navigate to your new plug-in location and select the top-level directory. If all goes well, it should appear in the list of available extension locations (Figure 9). 6. When you install a new plug-in, you are asked for the installation directory. Use your new plug-in location rather than the default. Now, when you upgrade Eclipse or WDSc, just use the Manage Configuration dialog box to reestablish the link to your plug-in. Craig Caulfield Senior development analyst Landmark Never Hand-Code a Procedure or D-Spec Again Two handy menu options available while using WDSc with RPG source ensure that you never again have to hand-code a procedure or D-spec for data structures. Use the menu items Source|Procedure and Source|D-specification and let WDSc do all the work. These two wizards guide you through a few panels of choices, and then they create and insert the code for you. Easy! Jef Sutherland System iNEWS technical editor Two Cool WDSc 7.x Tools

I've found two new features in WDSc 7 that I really like. First, place your cursor on any subroutine name or procedure name and press F3. The editor then places your cursor on the beginning of that subroutine or procedure. This makes it very easy to go to the beginning of the code doing the work! Second, for those RPGLE source code members that aren't free format yet (yes, I still have a few), I use the "Show open block" feature (Ctrl+Shift+O) to have WDSc draw nice arrowed lines that show the beginning and end of a control block (Figure 10). Put your cursor on a control block keyword such as select or if and press Ctrl+Shift+O to see for yourself! Press Ctrl+F5 to remove the "Show open block" lines. Jef Sutherland System iNEWS technical editor Quickly Open a Member in the Remote System Explorer The typical way to open a member in the Remote System Explorer (RSE) is to drill down to the member in the Remote Systems view, and then either double-click the member name or rightclick and select Open With|Remote Systems LPEX Editor. However, this approach can be both tedious and frustrating when you already know the exact name of the member you want to edit. In this situation, the RSE has an easier way to open a member: type the library, source file, and member name. This is the Open Member In Editor dialog box (Figure 11). You can open this dialog box using the Ctrl+Shift+A keyboard shortcut in the RSE or by right-clicking iSeries Objects and selecting Open Member. Also, if you select a library or source physical file before opening the dialog box, the library and file names are prefilled. Don Yantzi Technical lead WebSphere Development Studio Client for iSeries IBM Toronto Lab Keyboard Shortcuts in WDSc 7.0 One of the most frequent complaints about WDSc is the lack of documentation for keyboard shortcuts. New in WDSc 7.0 (actually this is a new Eclipse feature), a pop-up window shows all valid keyboard shortcuts in the current workbench context. To open this dialog box, use the Ctrl+Shift+L keyboard shortcut or select Help|Key Assist. For example, if you are debugging an RPG program and open the key assist dialog box, you can find that the shortcuts for the Step Into, Step Over, and Step Return actions are F5, F6, and F7, respectively (Figure 12). Don Yantzi Technical lead WebSphere Development Studio Client for iSeries IBM Toronto Lab Remote Text Searching Based on RSE Member Filter

Member filters in the RSE let you specify exactly which members you want to work with by using either a single filter string or multiple filter strings (you have to change the member filter after creating it before you can add additional filter strings). This functionality retrieves the exact list of members, even if they are in different libraries or source files, or if they don't follow similar name patterns. But did you know that you can also do text searches based on the members in a filter? Rightclick the member filter and select Find String from the pop-up menu. You are prompted for your search string, and then all members from the member filter are searched (on the remote system). The search results are displayed in the RSE's Remote Search view. Don Yantzi Technical lead WebSphere Development Studio Client for iSeries IBM Toronto Lab

You might also like