Does DS OVERLAY support VARCHAR sub-fields?

106 views Asked by At

Here's the source code

     Dcl-S dataString VarChar(1048576:4) Inz;
     Dcl-DS Ds_ErrMsg Qualified;
       ErrMsg      VarChar(249);  //22+1+21+1+200 = 245
                                  //extra 4 bytes for VarChar? What sub-fields exactly?
         date_iso    VarChar(22)  Inz('Error Date: ')
                                  Overlay(ErrMsg);
         *n          Char(1)      Inz(x'25') Overlay(ErrMsg:*Next);
         id          VarChar(21)  Inz('Error ID. . . . : ')
                                  Overlay(ErrMsg:*Next);
         *n          Char(1)      Inz(x'25') Overlay(ErrMsg:*Next);
         message     VarChar(200) Inz('Error. . . . : ')
                                  Overlay(ErrMsg:*Next);
     End-Ds;

     Ds_ErrMsg.date_iso += %Char(%Date);
     Ds_ErrMsg.id       += '100';
     Ds_ErrMsg.message  += 'No Response Received. ' +
                           'Call to test API ended in error.';

     dataString = Ds_ErrMsg.ErrMsg;

     *InLR = *On;

Below is the output

enter image description here

Expected Output

Error Date: 2023-11-15
Error ID. : 100
Error . . : No Response Received. Call to test API ended in error.

Also, the DS actually has 4 VARCHAR sub-fields, When declared size is 245, I get the following error during compile.

*RNF7303 30        001000  Subfield MESSAGE defined with keyword OVERLAY is too big;specification ignored.

Which makes sense, that I'd need to add Variable part of VARCHAR, so 2 bytes for each variable sub-field (2 bytes * 4 fields = 8 bytes), hence the new size should be 245+8 = 253 bytes i.e. VarChar(253), and the program also compiles when given the size of VarChar(249). Not sure how that worked!

2

There are 2 answers

1
nfgl On BEST ANSWER

You have 4 varchar fields but 3 of them overlay the other one so the size in bytes is 245 + 6 = 251 which is also the size of errmsg (249 + 2 = 251)

Btw the 2 bytes of date_iso overlay the 2 bytes of errmsg, so when you set Ds_ErrMsg.date_iso += %Char(%Date); you set the length of errmsg too. And when you use errmsg, it show data only for the length of date_iso

But DS_ERRMSG is defined as you coded :

EVAL ds_errmsg:c
DS_ERRMSG:C =                                                          
          ....5...10...15...20...25...30...35...40...45...50...55...60 
     1   ' █Error Date: 2023-12-04█ █Error ID. . . . : 100█ áError. . '
    61   '. . : No Response Received. Call to test API ended in error.'
   121   '                                                            '
   181   '                                                            '
   241   '           '                                                 

I think concatenation is a better tool for doing what you want to do. See %concat

1
Barbara Morris On

It's not a good idea to overlay varying length subfields over other varying length subfields. The big ErrMsg string has the 2-byte unsigned integers that hold the length for the overlaying subfields, and those 2 bytes would appear as garbage data in your ErrMsg string.

I agree that concatenation is a much better way to build up your message.

You probably don't even need your ErrMsg subfield. You can just set the value of dataString directly by concatenating the other three subfields.