Don't Be Misled by SETLL *LOVAL PDF Print E-mail
Programming - RPG
Written by Junlei Li   
Wednesday, 17 August 2011 00:00

Support MC Press - Visit Our Sponsors

Forums Sponsor

POPULAR FORUMS

Forums

Search Sponsor

Search

Be careful when using SETLL *LOVAL on keyed access paths containing numeric key fields.

 

Almost every RPG programmer has become accustomed to setting the file pointer to the starting position of a logical file by specifying the SETLL (Set Lower Limit) RPG operation code with figurative constant *LOVAL as the search argument operand, or similarly, setting the file pointer to the end of a logical file by specifying SETGT (Set Greater Than) with *HIVAL. The SETLL *LOVAL technique worked perfectly for decades, doing exactly what we RPG programmers expected. But is it always to be trusted everywhere?

 

The ILE RPG Language Reference manual mentions a few special conditions in which the SETLL *LOVAL will not work as it's supposed to. In this article, I will introduce you to things to consider before using SETLL *LOVAL.

 

  • It's a programming error to position to the beginning of a keyed physical or logical file containing numeric key fields with the UNSIGNED or ABSVAL keyword specified by using SETLL *LOVAL.
  • For a keyed PF or LF that has a floating-point key field, a SETLL *LOVAL operation cannot locate a record the value of whose float key field is -INF (negative infinity) or +INF (positive infinity).

What's the Actual Value of *LOVAL?

*LOVAL is an RPG figurative constant that can be specified as the value of the definition specification keyword INZ or the search-argument operand of operation code SETLL or SETGT. The actual value of *LOVAL is determined by the RPG compiler at compile time according to the actual data type of the data object being represented by *LOVAL. Using the following simple experiment, you can discover the actual values of *LOVAL determined for different numeric data types by the RPG compiler.

 

1. Set up a LF with three numeric key fields of type PKD(5,0), ZND(5,0), and 9-digit binary (4-byte binary), respectively.

2. Write a simple OPM RPG program that issues SETLL *LOVAL on the LF.

3. Compile the OPM RPG program with parameter GENOPT(*LIST).

 

Now, dig into the Generated Output section of the compiler listing, where you can find the MI instructions to initialize the actual key value represented by *LOVAL, like the following:

 

CPYBRAP .KEY(0001:0003), X'9D',X'99' /* SET KEY FIELD */

/*ZFIGCPY*/ ;

CPYBRAP .KEY(0004:0005), X'D9',X'F9' /* SET KEY FIELD */

/*ZFIGCPY*/ ;

CPYBLA .KEY(0009:4), X'C4653601' /* BIN(4) KFLD */

/*ZB4FIG*/ ;

 

 

 

The above MI instructions copy the actual values determined by the RPG compiler (for the PKD(5,0), ZND(5,0), and BIN(4) key fields) into character variable .KEY, which will be then used as the actual search argument of SETLL. The result value of .KEY is x'99999DF9F9F9F9D9C4653601'. So now you know the actual values that *LOVAL is translated into for different types of numeric data types:

 

  • x'9999...9D' (-99...9) for packed decimal
  • x'F9F9...D9' (-99...9) for zoned decimal
  • x'FFF7' (-9) for 1-digit binary, x'FF9D' (-99) for 2-digit binary, and so on. For example, x'D8F1' (-9,999) for 4-digit binary (2-byte binary) and x'C4653601' (-999,999,999) for 9-digit binary (4-byte binary).

 

Additionally, according to the ILE RPG Reference, *LOVAL is:

 

  • x'FF7FFFFF' (-3.4028234E+038) for 4-byte floating-point
  • x'FFEFFFFFFFFFFFFF' (-1.797693134862315E+308) for 8-byte floating-point

 

Similarly, you can find out the actual value of *HIVAL determined by the RPG compiler for different types of numeric data types.

 

Actual Value of *HIVAL

Data Type

Value

Hexadecimal Value

Packed decimal

+99...9

x'9999...9F'

Zoned decimal

+99...9

x'F9F9...F9'

N-digit binary

+99...9 (repeated for N times)

1-digit binary: x'0009'

2-digit binary: x'0063'

...

4-byte floating point

+3.4028235E+38

x'7F7FFFFF'

8-byte floating point

+1.797693134862315E+308

x'7FEFFFFFFFFFFFFF'

 

SETLL *LOVAL and Numeric Key Fields with the UNSIGNED Keyword Specified

Key fields defined as character fields (character, date, time, timestamp, and hexadecimal fields) are arranged based on the sequence defined for EBCDIC characters. Key fields defined as numeric fields are arranged based on their algebraic values, unless the UNSIGNED (unsigned value) or ABSVAL (absolute value) DDS keywords are specified for the field.

 

UNSIGNED is a key field-level keyword to specify that numeric fields are sequenced as a string of unsigned binary data. Note that the UNSIGNED keyword will be the default in the following situations:

 

  • When you specify ALTSEQ at the file level for a zoned key field
  • When you specify ZONE or DIGIT for a zoned key field
  • For all character and hexadecimal fields

 

Assume that you have a physical file LOVAL01 whose DDS source is the following:

 

R REC

A 8A COLHDG('CHAR_8')

PKD 5P 0 COLHDG('PKD_5_0')

ZND 5S 0 COLHDG('ZND_5_0')

BIN4 9B 0 COLHDG('BIN_4')

FLT4 9F 0 COLHDG('FLT_4')

 

 

 

 

 

 

 

 

There are three records in PF LOVAL01, like the following:

 

LOVAL01

RRN

CHAR_8

PKD_5_0

ZND_5_0

BIN_4

FLT_4

000001

REC-1

5-

5-

5-

-500000000.E-008

000002

REC-2

0

0

0

0.E+000

000003

REC-3

5

5

5

500000000.E-008

 

 

 

 

 

 

 

And there are four logical files—LF_PKD, LF_ZND, LF_BIN, and LF_FLT—based on PF LOVAL01. The logical files are "UNSIGNEDly" keyed by packed decimal field PKD, zoned decimal field ZND, binary field BIN4, and floating-point field FLT4, respectively. So records in the logical files are sequenced by the unsigned binary value of the numeric key fields, like the following:

 

LF_PKD

RRN

CHAR_8

PKD_5_0

Hex Value of PKD

000002

REC-2

0

x'00000F'

000001

REC-1

5-

x'00005D'

 

 

 

 

 

 

If you issue SETLL *LOVAL on LF_PKD to position to the beginning of LF_PKD, since the figurative constant *LOVAL is treated as x'99999D' for a PKD(5,0) field, the file pointer will be positioned to the end of LF_PKD. A READ operation after SETLL *LOVAL will encounter an EOF condition.

 

LF_ZND

RRN

CHAR_8

PKD_5_0

Hex Value of ZND

000001

REC-1

5-

x'F0F0F0F0D5'

000002

REC-2

0

x'F0F0F0F0F0'

 

 

 

 

 

Since *LOVAL is treated as x'F9F9F9F9D9' for a ZND(5,0) field, issuing SETLL *LOVAL on LF_ZND will position the file pointer to the end of LF_ZND.

 

LF_BIN

RRN

CHAR_8

BIN_4

Hex Value of BIN

000002

REC-2

0

x'00000000'

000003

REC-3

5

x'00000005'

 

 

 

 

 

Since *LOVAL is treated as x'C4653601' (-999,999,999) for a 9-digit (4-byte) binary field, issuing SETLL *LOVAL on LF_BIN will position the file pointer before record 1, and a following READ operation will retrieve record 1.

 

LF_FLT

RRN

CHAR_8

FLT_4

Hex Value of FLT

000002

REC-2

0

x'00000000'

000003

REC-3

5

x'40A00000'

 

 

 

 

 

Since *LOVAL is treated as x'FF7FFFFF' for a 4-byte floating-point field, issuing SETLL *LOVAL on LF_FLT will position the file pointer to the end of LF_ZND.

 

As you've seen in all the above conditions, SETLL *LOVAL cannot work as it is supposed to, positioning to the beginning of a file, with all four types of numeric key fields with the UNSIGNED keyword specified. For a packed decimal UNSIGNED key field, since all unsigned binary values of a packed decimal field are less than -999...99 (x'9999...9D') except 999...99 (x'9999...9F'), SETLL *LOVAL will bypass all records except the ones with value -999...99 or 999...99. Similarly, for a zoned decimal UNSIGED key field, a SETLL *LOVAL operation will bypass all records except those whose key value is -999...99 (x'F9F9...D9') or 999...99 (x'F9F9...F9'). For an n-digit binary UNSIGNED key field, a SETLL *LOVAL operation will bypass records whose key values are less than -99...9 (n digits). For a 4-byte or 8-byte floating-point UNSIGNED key field, a SETLL *LOVAL operation will bypass all records except the ones with value -INF or +INF.

SETLL *LOVAL and Numeric Key Fields with the ABSVAL Keyword Specified

ABSVAL is a key field-level keyword to direct the operating system to ignore the sign of the field when it sequences the values associated with this numeric field (in other words, records are sequenced by the absolute value of the numeric key field).

 

For a keyed access path containing a numeric key field with the ABSVAL keyword specified, the values of the numeric field are treated in the following manner:

 

1. First, the sign bits of the value of the key field are converted to positive values.

2. Then, the unsigned binary value of conversion is taken to build the access path.

 

For a zoned decimal value, the higher 4 bits of the right-most byte is set to hex F; for a packed decimal value, the lower 4 bits of the right-most byte is set to hex F; for a binary or floating-point value, the highest bit (sign bit) is cleared.

 

Similar to a SETLL *LOVAL operation on keyed PF or LF containing a numeric UNSIGNED key field, a SETLL *LOVAL operation on a keyed PF or LF containing a numeric key field with the ABSVAL keyword specified will:

 

  • Bypass all records except the ones with value -99...9 or 99...9 for a packed or zoned decimal key field
  • Bypass all records for a binary or floating point key field, since for binary or floating-point, *LOVAL is treated as a negative number (whose highest bit is 1) and the unsigned binary value of a negative number is always greater than that of a positive number or zero.

SETLL *LOVAL and -INF/+INF

In scientific computing, -INF and +INF make sense. For example, adding any number to INF should still be INF, dividing any number by INF should be zero. According to the ILE RPG Reference, when representing a 4-byte or an 8-byte floating-point value, figurative constants *LOVAL and *HIVAL are treated as values, as shown in the following table:

 

Value of *LOVAL and *HIVAL for Floating-Point

 

4-Byte Floating-Point

8-Byte Floating-Point

*LOVAL

x'FF7FFFFF'

x'FFEFFFFFFFFFFFFF'

*HIVAL

x'7F7FFFFF'

x'7FEFFFFFFFFFFFFF'

 

 

 

 

 

 

According to the IEEE standard (IEEE 754), the values of INFs for 4-byte and 8-byte floating-point data are the following:

 

Value of -INF and +INF for Floating-Point

 

4-Byte Floating-Point

8-Byte Floating-Point

-INF

x'FF800000'

x'FFF0000000000000'

+INF

x'7F800000'

x'7FF0000000000000'

 

 

 

 

 

 

Note that although the format of floating-point numbers are implementation-dependent, the floating-point format on IBM i conforms to the IEEE standard. The above-mentioned information can also be found in the documentation on Data Types and Limits on IBM i.

 

Through a simple RPG example program, you can see that the above-shown INF values can behave correctly when involved in computations, while the RPG figurative constants *LOVAL and *HIVAL cannot be used as positive or negative infinity. Consider the following RPG program, loval_inf.rpgle.

 

d a s 4f

* HUGE

d huge s 4f inz(*hival)

* INF

d ds

d c 4a inz(x'7F800000')

d inf 4f overlay(c)

 

/free

a = 2 ** 127; // a = 1.701411834605E+038

a /= huge; // a = 5.000000596046E-001 [1]

 

a = 2 ** 127;

a = huge - a; // a = 1.701411631781E+038 [2]

 

a = 2 ** 127;

a /= inf; // a = 0.000000000000E+000 [3]

 

a = 2 ** 127;

a = inf - a; // a = x'7F800000', +INF [4]

 

*inlr = *on;

/end-free

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

In the above example, the initial value of 4-byte floating-point variable a is 1.7014118E+038:

 

[1] Dividing a by *HIVAL is 0.5.

[2] Subtracting a from *HIVAL is 1.7014116E+038.

[3] Dividing a by +INF is zero.

[4] Subtracting a from +INF is still INF.

 

Since the absolute value of *LOVAL/*HIVAL is great the absolute value of -INF/+INF, a SETLL *LOVAL operation or a SETGT *HIVAL operation against a keyed PF or LF containing a floating-point key field obviously cannot locate records whose floating-point key field values are -INF or +INF, no matter that the floating-point key field has the SIGNED (by default), UNSIGNED, or ABSVAL keyword specified.

*START and *END

According to the "What's New in V4R4?" section in the ILE RPG Language Reference for V5R4, "The new *START and *END values for the SETLL operation code position to the beginning or end of the file." Note that unlike *LOVAL and *HIVAL, which are figurative constants, *START and *END are reserved words of the RPG language.

 

With the help of *START and *END, you can avoid the problems mentioned at the beginning of this article. Note that when using SETLL *START or SETLL *END, the name operand of SETLL can be only a file name, not a record format name. Assume that the records in a physical file called LOVAL05 that is keyed by a 4-byte floating-point field are like the following:

 

FLT(4) KEY FIELD A1

000001 0.E+000 +0

000002 -0.E+000 -0

000003 500000000.E-008 +5

000004 -500000000.E-008 -5

000005 *INF +I

000006 *NEGINF -I

 

 

 

 

 

 

 

 

The following RPG program loval06.rpgle can locate record -6 either by a SETLL *START operation followed by a READ operation or by a SETLL -INF operation followed by a READE -INF operation.

 

fLOVAL05 if e k disk

 

d ds

d a 4a inz(x'FF800000')

d neg_inf 4f overlay(a)

 

/free

setll *start LOVAL05;

read REC;

dsply 'INF REC' '' A1;

 

setll neg_inf REC;

reade neg_inf REC;

if not %eof();

dsply 'INF REC' '' A1;

endif;

 

*inlr = *on;

/end-free

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Now You Know

With this information in your arsenal, you can now use SETLL *LOVAL with confidence.

as/400, os/400, iseries, system i, i5/os, ibm i, power systems, 6.1, 7.1, V7, V6R1


Junlei Li
About the Author:

Junlei Li is a programmer from Tianjin, China, with 10 years of experience in software design and programming. Junlei Li began programming under i5/OS (formerly known as AS/400, iSeries) in late 2005. He is familiar with most programming languages available on i5/OS—from special-purpose languages such as OPM/ILE RPG to CL to general-purpose languages such as C, C++, Java; from strong-typed languages to script languages such as QShell and REXX. One of his favorite programming languages on i5/OS is machine interface (MI) instructions, through which one can discover some of the internal behaviors of i5/OS and some of the highlights of i5/OS in terms of operating system design.

 

Junlei Li's Web site is http://i5toolkit.sourceforge.net/, where his open-source project i5/OS Programmer's Toolkit (https://sourceforge.net/projects/i5toolkit/) is documented.

Read More >>
Last Updated on Tuesday, 16 August 2011 14:33
 
User Rating: / 12
PoorBest 
   MC-STORE.COM