Release 10.1A: OpenEdge Deployment:
Managing 4GL Applications

> ## RCODE–INFO handle

> The `RCODE-INFO` system handle lets you read the r-code CRC from an r-code file. You can use this value to:

> - Build a procedure security table, and then to verify the integrity of your application r-code against it.

> - Automatically install database schema trigger definitions in a deployment procedure that you run in a secure context.

> - Determine whether you need to recompile procedure files after a database change.

> - Determine whether procedure files have changed between different versions of your application.

> ##### Getting the r-code CRC

> To read the r-code CRC from an r-code file, first set the `FILE-NAME` attribute of the `RCODE-INFO` handle to the pathname of your r-code file. Then read the value of the `CRC-VALUE` attribute:

>     DEFINE VARIABLE rCRC AS INTEGER.
>     RCODE-INFO:FILE-NAME = "sports/crcust.r".
>     rCRC = RCODE-INFO:CRC-VALUE.

> Note: The `RCODE-INFO` handle cannot read the r-code CRC from a session compile. For source (`.p`) procedures, the `CRC-VALUE` attribute returns the Unknown value (`?`).

> ##### Example — Verifying application r-code integrity

> Be sure to verify the integrity of your application’s r-code.

> | To provide r-code integrity and security in your application:

> 1. Build the procedure security table, RcodeSecurity, with these fields:

> - Filename — `CHARACTER` field for the pathname of each r-code file.
> - CRC — `INTEGER` field for the r-code CRC of the specified r-code file.
> 2. Construct a text file, `crctable.dat`, that contains a list of the relative pathnames for all the secure procedures called by your application.

> 3. Compile and save the r-code for all the secure procedures in your application.

> 4. Run a procedure that contains code like this to build the RcodeSecurity table:

>     DEFINE VARIABLE i AS INTEGER.
>     DEFINE VARIABLE proc-name AS CHARACTER FORMAT "x(32)".
>     DEFINE VARIABLE rCRC AS INTEGER.

>     INPUT FROM "crctable.dat". /* List of r-code file pathnames */

>     i = 0.
>     REPEAT:
>         SET proc-name.
>         FIND RcodeSecurity WHERE Filename = proc-name NO-ERROR.
>         IF NOT AVAILABLE(RcodeSecurity) THEN
>             CREATE RcodeSecurity.
>         RCODE-INFO:FILE-NAME = proc-name.
>         SET RcodeSecurity.Filename = proc-name
>             RcodeSecurity.Crc = RCODE-INFO:CRC-VALUE.
>         i = i + 1.
>     END.

>     INPUT CLOSE.
>     MESSAGE i "procedure security records created".

> 5. At each point where you call a secure procedure in your application, insert this code:

>     FIND RcodeSecurity WHERE Filename = "secret.r".
>     RCODE-INFO:FILE-NAME = "secret.r".

>     IF RcodeSecurity.Crc = RCODE-INFO:CRC-VALUE THEN
>         RUN secret.
>     ELSE DO:
>         MESSAGE "Procedure secret.r is invalid.".
>         QUIT.
>     END.

> ##### Example — Deploying schema triggers

> The following procedure installs new schema trigger definitions in an existing database. It reads dump files that contain the new data for table and field metaschema trigger records and updates these records with the new trigger procedure names and CRCs:

> trload.p
>     /* trload.p */
>     DEFINE VARIABLE i AS INTEGER.
>     DEFINE VARIABLE event AS CHARACTER FORMAT "x(6)".
>     DEFINE VARIABLE proc-name AS CHARACTER FORMAT "x(32)".
>     DEFINE VARIABLE table-name AS CHARACTER FORMAT "x(32)".
>     DEFINE VARIABLE field-name AS CHARACTER FORMAT "x(32)".
>     DEFINE VARIABLE rCRC AS INTEGER.
>     INPUT FROM "_file-tr.dat". /* Table trigger data */
>     i = 0.
>     _fl-loop:
>     REPEAT:
>       SET table-name event proc-name.
>       RCODE-INFO:FILE-NAME = proc-name.
>       rCRC = RCODE-INFO:CRC-VALUE.
>       FIND _file WHERE _file-name = table-name.
>       FIND _file-trig WHERE _file-recid = RECID(_file) AND
>                             _event = event NO-ERROR.
>       IF AVAILABLE _file-trig THEN DO:
>         IF  _File-trig._Proc-name = proc-name
>         AND _File-trig._Trig-CRC  = rCRC THEN
>             NEXT _fl-loop.
>         ELSE DO:
>         /* Progress doesn’t let you modify a trigger record, so delete and
>            recreate. */
>           DELETE _File-trig.
>           CREATE _File-trig.
>           ASSIGN _File-trig._File-recid = RECID(_File)
>                  _File-trig._Event      = event
>                  _File-trig._Override = TRUE
>                  _File-trig._Proc-Name  = proc-Name
>                  _File-trig._Trig-CRC   = rCRC
>                  i = i + 1.
>         END.
>       END.
>     END.
>     INPUT CLOSE.
>     MESSAGE i "_file-trig records updated.".
>     INPUT FROM "_field-t.dat". /* Field trigger data */
>     i = 0.
>     _fld-loop:
>     REPEAT:
>       SET table-name field-name event proc-name.
>       RCODE-INFO:FILE-NAME = proc-name.
>       rCRC = RCODE-INFO:CRC-VALUE.
>       FIND _file WHERE _file-name = table-name.
>       FIND _field WHERE _file-recid = RECID(_file) AND
>                         _field-name = field-name.
>       FIND _field-trig WHERE _field-trig._file-recid = RECID(_file) AND
>                              _field-trig._field-recid = RECID(_field) AND
>                              _event = event NO-ERROR.
>       IF AVAILABLE _Field-trig
>           AND _Field-trig._Proc-name = proc-name
>           AND _Field-trig._Trig-CRC  = rCRC THEN NEXT _fld-loop.
>       ELSE DO:
>         DELETE _Field-trig.
>     CREATE _Field-trig.
>         ASSIGN
>           _Field-trig._File-recid  = RECID(_File)
>           _Field-trig._Field-recid = RECID(_Field)
>           _Field-trig._Event       = event
>           _Field-trig._Override    = TRUE
>           _Field-trig._Proc-Name   = proc-Name
>           _Field-trig._Trig-CRC    = rCRC
>           i = i + 1.
>       END.
>     END.
>     INPUT CLOSE.
>     MESSAGE i "_field-trig records updated.".

> Note: As this example shows, you must use the `RECID` function rather than the `ROWID` function to reference metaschema table record locations.

> ##### Example — Determining which files are affected by a database change

> The following procedure demonstrates how you can use the `RCODE-INFO` system handle with the `TABLE-LIST` and `TABLE-CRC-LIST` attributes to help determine which files you need to recompile based upon a database change. `TABLE-LIST` generates a list of all the database tables that are referenced in the procedure file. `TABLE-CRC-LIST` generates a list of the corresponding table CRC values stored in the compiled procedure file. This example procedure then compares the CRC values in the procedure file with those stored in the database. If any of the values differ, you get a message stating that the procedure needs to be recompiled, as shown:

>     DEFINE VARIABLE tbllst AS CHARACTER.
>     DEFINE VARIABLE crclst AS CHARACTER.
>     DEFINE VARAIBLE hBuff AS HANDLE.
>     DEFINE VARIABLE i AS INT.
>     RCODE-INFO:FILE-NAME = "main.r".
>     tbllst = RCODE-INFO:TABLE-LIST.
>     crclst = RCODE-INFO:TABLE-CRC-LIST.
>     REPEAT i = 1 TO NUM-ENTRIES(tbllst):
>        CREATE BUFFER hBuff FOR TABLE ENTRY(i, tbllst).
>        IF hBuff:CRC-VALUE = INTEGER(ENTRY(i, crclst))
>           THEN MESSAGE “main.r does not need to be recompiled”.
>        ELSE MESSAGE “main.r needs to be recompiled”.
>        DELETE OBJECT hBuff.
>     END.

> This procedure does not generate any warnings or error messages. If the r-code file was not compiled with any tables then the attribute returns the empty string. If the file is not found or is corrupted, the attribute returns the Unknown value (`?`).

> ##### Example — Determining which files differ between application versions

> The MD5 value is a 128-bit unique key that is stored within a compiled procedure. Changing one character in a procedure file results in a different MD5 value. With the `MD5-VALUE` attribute for the `RCODE-INFO` system handle, you can determine which r-code files need to be replaced in your application between versions. The following example code shows the output of the `MD5-VALUE` attribute:

>     DEFINE VARIABLE charmd5 AS CHARACTER.
>     RCODE-INFO:FILE-NAME = "main.r".
>     charmd5 = RCODE-INFO:MD5-VALUE.
>     MESSAGE "MD5 value of main.r: " charmd5.

> This code results in the following output:

>     MD5 value of main.r: E3AD5B5C009B8FA1C20067304161B6CC0D

> You could create a program that runs this code for two versions of the same procedure file and then compare the resulting outputs. If they are the same, you know the contents of the procedure file has not changed between the two versions.

> If you did not use the `GENERATE-MD5` option on the `COMPILE` statement to compile a procedure, Progress did not store the MD5 value in the r-code file. In this case, this attribute returns the Unknown value (`?`).

Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095