ILE RPG UUID functions

A UUID is a unique identifier which has an extremely low collision rate. This article explains some real-world uses for UUIDs. Here is the Wikipedia entry.

The first procedure simply retrieves the UUID itself. A UUID is nothing more than 16 hex bytes. Many applications, however, expect to see the “human representation” of the bytes in a standard format. A wrapper procedure will convert the UUID from hex to readable format.

The only downside to the i5/OS UUID (as of V5R4, I do not have access to a 6.1 machine to test) is it is a DCE version 1 UUID. The latest version as of this writing is version 5 with SHA-1 hashing.

Getuuid() procedure


     d getUUID         pr            16a

     p getUUID         b
     d getUUID         pi            16a

      // Implements DCE version 1 UUID
      // Source link:
      // http://publib.boulder.ibm.com/iseries/v5r1/ic2924/tstudio/tech_ref/mi/GENUUID.htm

      // Template structure required for _GENUUID.
     d UUID_template   ds
     d  UUID_bytes_provided...
     d                               10u 0 inz(%size(uuid_template))
     d  UUID_bytes_available...
     d                               10u 0
     d  UUID_reserved                 8a   inz(*allx'00')
     d  UUID_UUID                    16a

     d GenUUID         pr                  extproc('_GENUUID')
     d  UUID_Template                  *   value

      /free
         reset uuid_template;
         GenUUID(%addr(UUID_Template));
         return UUID_UUID;
      /end-free

     p getUUID         e

As mentioned above, many times it is more useful to get the UUID in a human readable format. With that in mind, here is a getUUIDString() procedure. It takes an optional parameter, a hex UUID (perhaps previous retrieved from getUUID). If a UUID is not passed, one will be retrieved automatically. The procedure also converts the text representation to lower case.

getUUIDString() procedure & helpers


     d getUUIDString   pr            36a
     d  inUUID                       16a   options(*nopass)

     p getUUIDString   b
     d getUUIDString   pi            36a
     d  inUUID                       16a   options(*nopass)

     d workuuid        s                   inz like(inuuid)
     d uuid_string     s             36a   inz

      // Convert hex to character API.
     d cvthc           pr                  extproc('cvthc')
     d  Result                    65534a   options(*varsize)
     d  Source                    32767a   options(*varsize)
     d  ResultSize                   10i 0 value

      // NLS convert case.
     d convertcase     pr                  extproc('QlgConvertCase')
     d  ctrlBlock                          const like(FRCB)
     d  inString                  65535a   const options(*varsize)
     d  outString                 65535a   options(*varsize)
     d  inLength                     10i 0 const
     d  apiErrorDS                  300a   options(*varsize)

      // Formatted request control block required by QlgConvertCase.
     d FRCB            ds                  qualified
     d  ReqType                      10i 0 inz(1)
     d  CCSID                        10i 0 inz(0)
     d  CvtTo                        10i 0 inz(0)
     d  Reserved                     10a   inz(*allx'00')

      // Helper constants for FRCB.
      // Uses request 1 (CCSID format): assumes lower case, job CCSID.
      // For more information about the control block, see:
      // http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/QLGCNVCS.htm
     d CvtToUpper      c                   0
     d CvtToLower      c                   1

      // Error code structure.
     d errc0100        ds
     d  errc01bytpro                 10i 0 inz(%size(errc0100))
     d  errc01bytava                 10i 0 inz
     d  errc01excid                   7a   inz
     d  errc01resaaa                  1a   inz(x'00')
     d  errc01excdta                250a   inz

      /free
         if %parms() = 1;
            workuuid = inuuid;
         else;
            workuuid = getuuid();
         endif;
         cvthc( uuid_string : workuuid : %len(workuuid)*2 );
         frcb.cvtto = cvttolower;
         reset errc0100;
         convertcase( frcb : uuid_string : uuid_string :
                      %len(uuid_string) : errc0100 );
         uuid_string = %subst(uuid_string:1:8) + '-' +
                       %subst(uuid_string:9:4) + '-' +
                       %subst(uuid_string:13:4) + '-' +
                       %subst(uuid_string:17:4) + '-' +
                       %subst(uuid_string:21:12);
         return uuid_string;
      /end-free

     p getUUIDString   e

A few things going on in getUUIDString. It uses IBM QlgConvertCase API to convert the text to lower case (it can also do upper case), no %xlate() functions here. This is the “correct” way to convert case to respect CCSID. Also uses the cvthc API to convert the hex values to text representation. Personally I have not needed the function in normal programming, but it is also used to generate a human readable MD5 hash. Converting hex to character just doesn’t come up often in business programming. Lastly, it shows proper use of the error code parameter. All too often, developers leave the “bytes provided” parameter uninitialized. This translates to x’404040′ or a very large number. Just as often, it will be set to zero, which prevents the error structure from being populated.

Code sample usage



      // Copy in the procedures above.

      // Generate UUID and alpha representation
     h option(*srcstmt : *nodebugio) dftactgrp(*no) bnddir('QC2LE')

     d getUUID         pr            16a
     d getUUIDString   pr            36a
     d  inUUID                       16a   options(*nopass)

     d myuuid          s             16a   inz
     d myuuidstring    s             36a   inz

      /free
         myuuidstring = getuuidstring();
         myuuid = getuuid();
         myuuidstring = getuuidstring(myuuid);
         *inlr = *on;
         return;
      /end-free