星期四, 11月 02, 2023

2002-08-27 如何存取任一工作 QTEMP 程式館的物件?


如何存取任一工作 QTEMP 程式館的物件?

當使用者從 SignOn 畫面輸入使用者代碼及密碼後,進入系統的同時
系統會自動給予一組由工作站名稱 Jobname,使用者代碼 User,及工
作編號 Jobnbr,組成一個存於系統中的唯一代碼即"JOBNBR/USER/JOBNAME"
,當成系統用以辨別系統中每個工作的代碼,也同時依照該代碼於記
憶體中新增一個 QTEMP 程式館供該工作臨時使用,而當該工作結束作
業(SignOff)時,系統也自動將該工作的 QTEMP 程式館刪除,所以
QTEMP 是進入系統每個工作的臨時工作區僅供每個工作本身使用。

但若有需要存取任一工作 QTEMP 程式館的物件時,如某個工作狀態是
MSGW(有錯誤訊息,等待人工介入)時,就需要除錯或採取適當的回複
動作,如某些處理內容是存於 QTEMP 程式館中,有需要存取或修改讓
該工作能持續或僅是程式館路徑(library list)中缺一個程式館而找不
到正確的資料庫時,系統管理或程式人員可以利用執行遠端指令修正錯
誤讓程式繼續執行,此時使用者針對錯誤訊息應該回 "r" 重試,而不是
回 "c"取消。

可以利用二種方式存取任一工作 QTEMP 程式館的物件:

方式一:
  設定工作站訊息佇列(workstation message queue)的回應方式為中
    斷(*BREAK)模式,並使用中斷訊息處理理程式(break-handling program)
  ;當訊息抵達工作站訊息佇列時,中斷訊息處理理程式接收含有指令
  的訊息,並執行從訊息中擷取的指令,即可完成。但這個方式僅適用
  於線上即時的工作,並不適用於批次工作;你不能從另一個工作傳送
  訊息至批次作業。然而使用這個方式也需要於使用者初始程式中設定
  設定工作站訊息佇列(workstation message queue)的回應方式為中斷
  (*BREAK)模式,這個方式較麻煩及僅適用於線上即時的工作。
  
  Job1               Job2 使用者初始程式設定工作站訊息佇列中斷
              (*BREAK)模式及中斷訊息處理理程式
    送指令訊息 ==>    工作站訊息佇列
                          ||
                          || 
                          \/
                        中斷訊息處理理程式接收含有指令的訊息並執行
            從訊息中擷取的指令


方式二:(在此我以方式二作一個範例)
  這個方式適用於任何一種工作型態,線上即時式或批次,而且不需要其他
  額外的設定,使用上較容易;它包含三個部分,一個指令(RUNJOBCMD), 
  一支指令處理程式(SNDCMDCL) 及一支執行 RUNJOBCMD 所發出指令的跳出
  程式 exit program (RCVCMDCL)。

  Job1                     Job2
    RUNJOBCMD('job2' 'command mesage')  
    SNDCMDCL ======> Data Queue ==>  RCVCMDCL 程式指定於
   /\    發出指令訊息            指令TRCJOB
   ||            ||  /\       參數 EXITPGM 中
   ||===========||  ||       接收訊息指令
       接收回傳訊息    ||<===== 並執行訊息指令
                   回傳訊息
  
  處理權限如下:
  1: 發出指令訊息的使用者(Job1 的使用者)對執行訊息指令的使用者
     (Job2 的使用者)設定檔要有 *USE 的權限。

  2: 發出指令訊息的使用者(Job1 的使用者)對指令 STRSRVJOB,
     ENDSRVJOB,TRCJOB 要有 *USE 的權限。這些指令的預設公共權限
     是 *EXCLUDE。

  3: 或發出指令訊息的使用者(Job1 的使用者)有 *SERVICE 特殊權限。

  程式碼如下:

  RUNJOBCMD 指令接收二個參數,iSeries 400 的工作(即要執行內含指令訊
  息的工作)及所要執行的指令(這個指令將於參數一所指定的工作中執行)。 
  它並不在執行 RUNJOBCMD 指令的現有工作(current job)中執行。

  /* Command.....: RUNJOBCMD                                       */
  /* Description.: Runs a command on another job                   */
  /* Compile.....: CRTCMD CMD(QGPL/RUNJOBCMD) PGM(QGPL/SNDCMDCL) + */
  /*                  SRCFILE(YOURLIB/QCMDSRC)                     */
  /*                                                               */
             CMD        PROMPT('Run job command')                  
             PARM       KWD(JOBNAME) TYPE(*CHAR) LEN(10) MIN(1) +  
                          CHOICE('Name') PROMPT('Job name')        
                                                                   
             PARM       KWD(JOBUSER) TYPE(*CHAR) LEN(10) MIN(1) +  
                          CHOICE('Name') PROMPT('Job user')        
             PARM       KWD(JOBNUMBER) TYPE(*CHAR) LEN(6) +        
                          RANGE('000000' '999999') MIN(1) +        
                          CHOICE('000000 - 999999') PROMPT('Job +  
                          number')                                 
             PARM       KWD(COMMAND) TYPE(*CHAR) LEN(512) MIN(1) + 
                          CHOICE('Name') PROMPT('Command to run')


  SNDCMDCL 程式是 RUNJOBCMD 指令的處理程式,它會藉由啟動一個服務需要求
  (service request) 中斷 iSeries 400 的工作,然後以 資料佇列(Data queue)
  的方式傳送要被執行的指令訊息,當發出的指令訊息於另一個工作執行完成後,
  若有錯誤會通知發出指令訊息的使用者(Job1 的使用者)。

  /* Program.....: SNDCMDCL                                      */    
  /* Description.: CPP for RUNJOBCMD. Sends command to execute   */    
  /*               via data queue.                               */    
  /* Compile.....: CRTCLPGM PGM(QGPL/SNDCMDCL) +                 */    
  /*                  SRCFILE(YOURLIB/QCLSRC)                    */    
  /*                                                             */    
             PGM        PARM(&JOBNAME &USER &JOBNO &CMD)             
             DCL        VAR(&JOBNAME)  TYPE(*CHAR) LEN(10)           
             DCL        VAR(&USER)     TYPE(*CHAR) LEN(10)           
             DCL        VAR(&JOBNO)    TYPE(*CHAR) LEN(06)           
             DCL        VAR(&CMD)      TYPE(*CHAR) LEN(512)          
             DCL        VAR(&MSG)      TYPE(*CHAR) LEN(132)          
             DCL        VAR(&LEN)      TYPE(*DEC)  LEN(5 0) VALUE(80)
                                                                     
             DCL        VAR(&SNDDTAQ)  TYPE(*CHAR) LEN(10)           
             DCL        VAR(&RCVDTAQ)  TYPE(*CHAR) LEN(10)           
             DCL        VAR(&WAIT)     TYPE(*DEC)  LEN(5 0) VALUE(15)
             MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))      
                                                                     
  /* Creates data queue to send command and receive messages     */    
             CHGVAR     VAR(&SNDDTAQ)  VALUE('SND' || &JOBNO)        
             CHGVAR     VAR(&RCVDTAQ)  VALUE('RCV' || &JOBNO)        

                                                                      
             CHKOBJ     OBJ(&SNDDTAQ) OBJTYPE(*DTAQ)                  
             MONMSG     MSGID(CPF9801) EXEC(DO)                       
             CRTDTAQ    DTAQ(QGPL/&SNDDTAQ) MAXLEN(512) TEXT('Send +  
                          Command Data Queue')                        
             CRTDTAQ    DTAQ(QGPL/&RCVDTAQ) MAXLEN(512) TEXT('Status +
                          Data Queue')                                
             ENDDO                                                    
                                                                      
  /* Clear data queue just in case & sends the command to run      */   
             CALL       PGM(QCLRDTAQ) PARM(&SNDDTAQ 'QGPL')           
             CALL       PGM(QCLRDTAQ) PARM(&RCVDTAQ 'QGPL')           

             CALL       PGM(QSNDDTAQ) PARM(&SNDDTAQ 'QGPL' &LEN &CMD)
                                                                     
  /* Interrupts the job and executes the command                   */  
             STRSRVJOB  JOB(&JOBNO/&USER/&JOBNAME)                   
             TRCJOB     SET(*ON) MAXSTG(1024) EXITPGM(QGPL/RCVCMDCL) 
                                                                     
  /* Wait for indication that the command has completed processing */  
             CALL       PGM(QRCVDTAQ) PARM(&RCVDTAQ 'QGPL' &LEN &MSG 
                          &WAIT)                                     
             DLYJOB     DLY(2)                                       
             TRCJOB     SET(*END) MAXSTG(1024)                       
                                                                     
  /* End servicing job and interrupt                               */  
             ENDSRVJOB                                               
                                                                     
  /* Receive the completion messages                               */  
             CHGVAR     VAR(&WAIT) VALUE(0)                          
   RCVMSG: CALL       PGM(QRCVDTAQ) PARM(&RCVDTAQ 'QGPL' &LEN &MSG 
                          &WAIT)                                     
             IF         COND(&LEN *EQ 0) THEN(GOTO CMDLBL(CLEANUP))  
             SNDPGMMSG  MSG(&MSG)                                    
             CHGVAR     VAR(&MSG) VALUE(' ')                         
             GOTO       CMDLBL(RCVMSG)                               

  /* Error occurred within this program, so just send error message*/
   ERROR:  RCVMSG     MSGTYPE(*EXCP) RMV(*NO) MSG(&MSG)          
             SNDPGMMSG  MSG(&MSG)                                  
                                                                   
   CLEANUP: DLTDTAQ    DTAQ(QGPL/&SNDDTAQ)                        
             MONMSG     MSGID(CPF0000)                             
                                                                   
             DLTDTAQ    DTAQ(QGPL/&RCVDTAQ)                        
             MONMSG     MSGID(CPF0000)                             
                                                                   
   ENDIT:  ENDPGM        

  於指令 TRCJOB 參數 EXITPGM 所指定的跳出程式 RCVCMDCL,將執行在 TRCJOB 
  Job 參數所指定的工作下,即是 RUNJOBCMD 指令的 Job 指定值,它從資料佇列
  (Data Queue)擷取指令訊息,並執行所擷取的指令,也將完成訊息藉由資料佇列
  (Data Queue)回傳。

  /* Program.....: RCVCMDCL                                      */   
  /* Description.: Receives command from data queue and          */   
  /*               excecutes it via QCMDEXC                      */   
  /* Compile.....: CRTCLPGM PGM(QGPL/RCVCMDCL) +                 */   
  /*                  SRCFILE(YOURLIB/QCLSRC)                    */   
  /*                                                             */   
             PGM        PARM(&DUMMY)                                
             DCL        VAR(&DUMMY)    TYPE(*CHAR) LEN(100)         
             DCL        VAR(&JOBNO)    TYPE(*CHAR) LEN(06)          
             DCL        VAR(&CMD)      TYPE(*CHAR) LEN(512)         
             DCL        VAR(&MSG)      TYPE(*CHAR) LEN(132)         
             DCL        VAR(&CLEN)     TYPE(*DEC)  LEN(15 5)        
                                                                    
             DCL        VAR(&SNDDTAQ)  TYPE(*CHAR) LEN(10)          
             DCL        VAR(&RCVDTAQ)  TYPE(*CHAR) LEN(10)          
             DCL        VAR(&LEN)      TYPE(*DEC)  LEN(5 0)         
             DCL        VAR(&WAIT)     TYPE(*DEC)  LEN(5 0) VALUE(0)
             MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(ENDIT))     
                                                                    
             RTVJOBA    NBR(&JOBNO)                                 
             CHGVAR     VAR(&RCVDTAQ) VALUE('SND' || &JOBNO)        
             CHGVAR     VAR(&SNDDTAQ) VALUE('RCV' || &JOBNO)        

                                                                      
  /* Receive command from data queue                             */     
             CALL       PGM(QRCVDTAQ) PARM(&RCVDTAQ 'QGPL' &LEN &CMD +
                          &WAIT)                                      
                                                                      
  /* Runs the command                                            */     
             IF         COND(&LEN *EQ 0) THEN(GOTO CMDLBL(ENDIT))     
             CHGVAR     VAR(&CLEN) VALUE(&LEN)                        
             CALL       PGM(QCMDEXC) PARM(&CMD &CLEN)                 
             MONMSG     MSGID(CPF0000)                                
                                                                      
  /* Indicates command completion and sends completion messages  */     
             CHGVAR     VAR(&LEN) VALUE(1)                            
                                                                      
   SENDMSG: CALL       PGM(QSNDDTAQ) PARM(&SNDDTAQ 'QGPL' &LEN &MSG) 
             RCVMSG     RMV(*NO) MSG(&MSG) MSGLEN(&LEN)               
             IF         COND(&MSG *NE ' ') THEN(GOTO CMDLBL(SENDMSG)) 
                                                                      
   ENDIT:  ENDPGM        


  使用範例:

  RUNJOBCMD JOBNAME(FINGLPOST)
       JOBUSER(FINUSER)
       JOBNUMBER(123456) 
       COMMAND('DSPOBJD OBJ(QTEMP/*ALL) OBJTYPE(*ALL) OUTPUT(*PRINT)')
  
  上述使用範例是將批次工作 FINGLPOST 的 QTEMP 程式館中物件細系列出。
  因為這份報表是使用者 FINUSER 所產生的,所以要使用 WRKSPLF USER(FINUSER)
  指令才能瀏覽上述指令所產生的 QTEMP 物件明細表。

            



沒有留言: