Sponsored Links
Sponsored Link

sponsored links



No announcement yet.

Receiving messages earlier in the queue

  • Filter
  • Time
  • Show
Clear All
new posts

  • Receiving messages earlier in the queue

    Hi All

    I have a CPYFRMIMPF statement and I would like to provide some error handling.

    I thought that I had found a complete answer here: https://www.itjungle.com/2009/11/18/fhg111809-story02/

    But it's not working for me.

    The problem is that if I receive the last three messages, one after the other, it skips over the one I want. I contrived an error (added an extra comma in one record of the .csv), which results in one field's data not matching the target file field. Here are the last messages in the joblog:

    1. Member GBLUP file GBLUP in QGPL cleared. (CPC3101 - Completion)
    2. Current library changed to QGPL. (CPC2198 - Completion)
    3. Member LSOUTPUT for file LSOUTPUT in library QGPL not found. (CPF5815 - Diagnostic)
    4. The copy did not complete for reason code 9. (CPF2845 - Diagnostic)
    5. 55 records copied to member GBLUP. (CPC2959 - Completion)
    6. End of file detected for file LSOUTGBL in QGPL. (CPF0864 - Escape )

    Now ... I'm interested in CPF2845 (No.4), which tells me everything I need to know in the second level text, but it doesn't get returned by RCVMSG. When I debug the program, I get for each of three RCVMSG statements:

    CPF2817 (Monitored for, so not above) Message Type: 15 - Escape (exception already handled at time of RCVMSG)
    CPC2959 (Number 5 above) Message Type 01 - Completion
    CPC3101 (Number 1 above) Message Type 01 - Completion

    The article I cite above indicates that it should work for diagnostic messages, which is the type I want, but it simply doesn't. It jumps right over two of them.

    Any feedback welcome.

  • #2
    The weird thing is the diagnostic message that you're after does not get sent to the CL program like the escape message does, it actually gets sent to an OS program called QDBCTHREAD. You can retrieve the message with the RCVMSG command if you use the MSGTYPE(*PRVJLMSG) parameter (I believe that option was available as of 7.2). Here is a sample program that will find the last diagnostic message in the job log and send it to the caller:

                 DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)
                 DCL        VAR(&MSGF) TYPE(*CHAR) LEN(10)
                 DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(99)
                 DCL        VAR(&MSGTYPE) TYPE(*CHAR) LEN(2)
                 DCL        VAR(&MSGKEY) TYPE(*CHAR) LEN(4) +
                 CPYFRMIMPF FROMSTMF('/streamfile.txt') +
                              TOFILE(tofile) MBROPT(*REPLACE) RCDDLM(*ALL)
                 MONMSG     MSGID(CPF2817) EXEC(DO)
                 DOUNTIL    COND(&MSGTYPE = '02')
                              KEYVAR(&MSGKEY) MSGDTA(&MSGDTA) +
                              MSGID(&MSGID) RTNTYPE(&MSGTYPE) MSGF(&MSGF)
                 IF         COND(&MSGTYPE = '02') THEN(SNDPGMMSG +
                              MSGID(&MSGID) MSGF(&MSGF) MSGDTA(&MSGDTA) +


    • #3
      Thanks very much. Although I can't implement this immediately I'll put it aside for later. The customer is currently at 7.1 and has to upgrade a third-party package before they can upgrade iOS. They'll be forced to when support ceases so it shouldn't be too far off.

      Meanwhile it eases my frustration to know there's a reason for it.

      Also, the DOUNTIL is much more elegant and flexible than a series of RCVMSG commands. Somehow I missed the introduction of that, so there's a bonus for me.


      • #4
        Yeah, the first time I ran into this, I was confused as well. But, the idea is that there are multiple call-levels, and each one has it's own separate message queue. The job log is a compilation of all of them, so you'll see everything there, but most other tools that read messages only read one queue at a time. (Such as RCVMSG, message subfiles, etc.)

        On earlier releases I used some other ways of getting all the messages....

        1) You may consider this a "kludge", but I would send a message to get the message key before calling a 3rd party routine, then send a message to get the key afterwards. Then I'd loop through all possible keys in between, and receive those messages by their key. Granted, a lot of the possible keys didn't exist -- but this was a way to get every message that did exist while the 3rd party program was running.

        2) IBM supplies a QMHLJOBL API that can be used to retrieve the entire contents of the job log. This can work well, but it's more advanced programming than a lot of CL programmers are used to.

        Of course, the newer *PRVJLMSG option is a good way, too... but requires a new-ish release.


        • #5
          Originally posted by Scott Klement View Post
          2) IBM supplies a QMHLJOBL API that can be used to retrieve the entire contents of the job log. This can work well, but it's more advanced programming than a lot of CL programmers are used to.
          Well now ... here's something that doesn't happen very often. While using The Google to look for examples of QMHLJOBL I stumbled across this post taking a different tack:

          So I thought it was worth a quick try since the CL in question is already set up for easy debugging. And it works like a charm (at least for my requirements). Here's the relevant code:

          cpyfrmimpf fromstmf( &fromifs ) +                             
                     tofile(GBLUP )  rcddlm(*CRLF)                +     
                     errrcdfile(QTEMP/ERRRCD ) rmvcolnam(*YES) +        
           monmsg  CPF2817  *n  do                                      
            RUNSQL SQL('create table QGPL.GBLLOG (LVL1, LVL2) +         
                        as (  SELECT char(MESSAGE_TEXT), +              
                              char(MESSAGE_SECOND_LEVEL_TEXT) +         
                        from  table(QSYS2.JOBLOG_INFO(''*'')) a +       
                        where A.MESSAGE_TYPE = ''DIAGNOSTIC'' +         
                        order by ORDINAL_POSITION desc +                
                              fetch first 1 row only  ) +               
                                               with data') commit(*NONE)
          So, this one-record file with the first and second level text, plus the ERRRCDFILE I'm already generating, give me, respectively, the exact nature of the error and the offending record, in two files that I can either read in some other process or just email as attachments, either to myself or to the perpetrator of the outrage.



          • #6
            For those playing along at home, here is an example of how the error message Second Level text (see post above for how it's created) can be emailed.

                dclf GBLLOG                                                          
                dcl  &emlmsg   *char  5000               /* Email Message Text     */
            /* Replace &N with the SNDDST code for New Line in the email body      */
                runsql     sql('UPDATE QGPL/GBLLOG SET LVL2 = +                      
                                replace(LVL2, ''&N '', '':/N'' ) ') +                
            /* Replace &P with the SNDDST code for New Paragraph in the email body */
                runsql     sql('UPDATE QGPL/GBLLOG SET LVL2 = +                      
                               replace(LVL2, ''&P'', '':/P'' ) ') +                  
                 monmsg   (cpf0864 cpf4102) *n  (goto exit)                          
                chgvar &emlmsg &LVL2                                                
               (Send the email here with &emlmsg as the long message - I have my own utility based on SNDDST)


            sponsored links