Supported RPG Features

Character comparisons (=, <>, <, >, <=, >=) are blank-insensitive: both operands are conceptually right-padded with blanks to the length of the longer operand before comparing, matching IBM i. So a CHAR(5) holding 'AB' (stored 'AB ') compares equal to the literal 'AB', and two fixed CHAR fields of different declared widths compare on their blank-padded values. This padding applies to VARYING operands as well - character comparison is not length-sensitive. (Trailing blanks are significant only where the value's bytes are inspected directly, e.g. %LEN or bracketed concatenation.)

Collating order is EBCDIC, not ASCII. Every ordered comparison of character data uses the EBCDIC sequence - regardless of the JVM's native (Unicode/ASCII) character order. This applies uniformly across:

The same character data therefore orders identically no matter which of these operations inspects it. The relevant ordering of common groups is:

blank  <  most specials  <  lowercase a - z  <  uppercase A - Z  <  digits 0 - 9

This is the opposite of ASCII for two cases that frequently surprise developers porting code: lowercase letters sort before uppercase ('a' < 'A'), and digits sort after letters ('A' < '9'). For example 'apple' sorts before 'Apple', and SORTA on ['A1','a1','01'] yields ['a1','A1','01']. Equality comparisons (=, <>) are unaffected by collation. The figurative constants *HIVAL and *LOVAL remain the highest and lowest collating values (x'FF' and x'00').

Per-field CCSID. A character field's CCSID(...) keyword selects the code page its bytes are in, and that code page governs how the field's characters collate. This is honored for every code page in the supported set - the SBCS EBCDIC pages 37, 273, 277, 278, 280, 284, 285, 297, 500, 871 and 1047 plus the Euro variants 1140 - 1147, the SBCS ASCII pages 819 and 850 (and CCSID(0), the job default, which resolves to 37) - and for UTF-8 (CCSID(1208), equivalently CCSID(*UTF8)); a field with no CCSID keyword uses the default page (37) when collated against another field that also has no CCSID (see the mismatched-CCSID rule below for how it collates against an explicit-CCSID field). Because a character's EBCDIC byte value differs between code pages, two fields declared with different CCSIDs can order the same characters in opposite directions - for example the circumflex (^) and underscore (_) collate ^ > _ under CCSID 37 but ^ < _ under CCSID 1047.

The symbolic keyword forms are recognized in both source formats: CCSID(*UTF8) is UTF-8 (1208), and CCSID(*JOBRUN) and CCSID(*DFT) select the job CCSID - the same page as a field with no CCSID keyword. CCSID(*HEX) (raw byte data exempt from conversion), CCSID(*JOBRUNMIX) (the job's mixed-byte DBCS-capable page), a UCS-2 CCSID (13488, 1200 - not valid on a character field), and any unrecognized symbolic value are rejected at compile time (TRN3022) rather than silently mis-collated.

A UTF-8 field collates in Unicode code-point order, and it makes every comparison it appears in collate that way - including one against a field with no explicit CCSID (matching IBM i). Likewise, when the two operands of a comparison carry mismatched CCSIDs, the comparison collates in Unicode (UCS-2) code-point order rather than under either operand's page, so the result is independent of which operand is written first. "Mismatched" covers both two different explicit EBCDIC pages and one explicit EBCDIC page against a field with no CCSID keyword (the job default) - the latter collates in Unicode even when the explicit page happens to equal the job default, because it is the difference in whether a CCSID is specified, not its numeric value, that forces the reconciliation. Two operands that share a CCSID - both with no CCSID keyword, or both the same explicit page - still collate under that EBCDIC page. For example, 'A' and '1' collate 'A' < '1' under every EBCDIC page but 'A' > '1' in Unicode order - the order a CCSID(1208) operand, a two-different-CCSID comparison, or a no-CCSID-vs-explicit-CCSID comparison produces. The figurative constants keep their extreme positions under Unicode collation: *HIVAL still compares higher, and *LOVAL lower, than any character value.

A character array's per-field CCSID governs its array-collation operations the same way it governs a comparison: SORTA (ascending and DESCEND) and the ordered searches %LOOKUPGT / %LOOKUPGE / %LOOKUPLT / %LOOKUPLE (and the fixed-format LOOKUP opcode with a high/low resulting indicator) collate a CCSID(1208) / *UTF8 array in Unicode code-point order and an explicit-EBCDIC-page array under that page. So SORTA of a CCSID(1208) array holding 'A', '1', 'a' yields '1', 'A', 'a' (Unicode), where a default-page array yields 'a', 'A', '1'. An array with no CCSID keyword sorts and searches under the default page. (Plain %LOOKUP equality, which does not depend on collation, is unaffected either way.)

The zone and bit opcodes (BITON, BITOFF, TESTB, TESTN, TESTZ, and the MHHZO/MHLZO/MLHZO/MLLZO zone moves) also honor the field's CCSID: they operate on the byte the character has under the field's own code page, matching IBM i. A variant character such as ^ is x'B0' under CCSID 37 but x'5F' under 1047, so BITON X'20' on a CCSID(1047) field holding ^ produces " (x'7F'), while the same operation on a CCSID 37 field leaves it unchanged. On a CCSID(1208) field these opcodes operate on the field's UTF-8 bytes. When a 1-byte character field supplies the mask in Factor 2, its byte is likewise read under that field's own CCSID.