DB2 z/OS Code - Detail View


Date

Name

Plattform

Language

Kurzbeschreibung

Owner

Link

16.10.2001

APPLYIS.REXX

OS/390

REXX

Data Propagator Steuerung

Gernot Ruban

 

DB2 ist ein Produkt der
IBM Corporation. Bitte
Copyright-  und Trademark-Hinweise beachten!

 /*REXX****************************************************************/
 /* APPLYIS....: DPropR Apply V5 Information and Control              */
 /*-------------------------------------------------------------------*/
 /* CALLED BY..: IKJEFT01   - TSO online or batch                     */
 /* ARGUMENTS..: SSID     I - DB2 Subsystem ID                        */
 /*              ASNQUAL  I - Apply Qualifier and opt. SET name       */
 /*              OPTION   I - SUBS  list subscriptions                */
 /*                       I - TRAIL list log (APPLYTRAIL)             */
 /*                       I - CHECK check sub's success               */
 /*                       I - WATCH watch sub's processing for n secs */
 /*                       I - MAINT deletes from APPLYTRAIL           */
 /*                       I - ACT   activate subscriptions            */
 /*                       I - DEACT deactivate subscriptions          */
 /*                       I - EVENT add an event timestamp            */
 /* CALLS......: RXSQL    M - REXX to SQL Interface                   */
 /*              D2PABND  M - batch only: abend job step              */
 /*              anyWAIT  M - platform standard WAIT program          */
 /*              SEND     C - TSO SEND command                        */
 /* FILES......: SYSTSPRT O - Information                             */
 /*-------------------------------------------------------------------*/
 /* FUNCTION...: This TSO/E REXX procedures reads information from    */
 /*              Data Propagator tables, which can be used to         */
 /*              control dependent process flow.                      */
 /*-------------------------------------------------------------------*/
 /* COMMENTS...: Remind, when comparing LASTRUN and LASTSUCCESS, that */
 /*              Apply does not set microseconds in LASTSUCCESS.      */
 /*-------------------------------------------------------------------*/
 /* HISTORY....: 29.09.98/GR - V1R0 Gernot Ruban                      */
 /* 98-10-09/GR: IWWTO replaced by TSO SEND to CN(00),           V1.1 */
 /*              anyWAIT instead of timer function,                   */
 /*              tolerance for WATCH functions, new functions ACT,    */
 /*              DEACT and EVENT. MAINT expanded for events.          */
 /* 98-10-19/GR: WAIT-Select corrected                           V1.1 */
 /* 98-12-02/GR: SYNCHRONIZE and opt. parm setname added         V1.2 */
 /* 99-01-12/GR: STOP added, new parms for MAINT and EVENT       V1.3 */
 /* 99-01-20/GR: problem with event time fixed, new parameter    V1.4 */
 /*              EVENT RESTART added                                  */
 /*********************************************************************/
 x = MSG("OFF")
 
 /********************************************************************/
 /* Initial values                                                   */
 /********************************************************************/
 version   = "V1.4";    /* Current version                           */
 tolerance = "2 HOURS"; /* Set watching time tolerance default value */
 
 /********************************************************************/
 /* Check arguments passed                                           */
 /********************************************************************/
 parse upper arg ssid "," asnqual "," option "," debug
 If   ssid = "",
 !  ( option <> "SUBS" ,
    & option <> "TRAIL" ,
    & option <> "CHECK" ,
    & pos("WATCH",option) = 0,
    & pos("MAINT",option) = 0,
    & pos("EVENT",option) = 0,
    & option <> "ACT" ,
    & option <> "DEACT" ,
    & option <> "SYNCH" ,
    & option <> "STOP" ,
    & option <> "" )
 then signal syntax
 
 if pos("WATCH",option) > 0
 then do
      if words(option) > 1
      then do
           wtime     = word(option,2)
           if words(option) > 2
           then tolerance = subword(option,3)
           option    = "WATCH"
           if verify(wtime,"0123456789") > 0
           then signal syntax
      end
      else wtime = 60                /* dflt watch time in minutes */
 end
 
 if pos("MAINT",option) > 0
 then do
      if words(option) > 1
      then mtime     = subword(option,2)
      else mtime     = ""
      option = "MAINT"
 end
 
 if pos("EVENT",option) > 0
 then do
      if words(option) > 1
      then do
           etime     = word(option,2)
           option    = "EVENT"
           if etime <> "RESTART",
           &  verify(etime,"0123456789") > 0
           then signal syntax
      end
      else etime = ""                /* dflt event time            */
 end
 
 if debug = "DEBUG"
 then trace ?I
 
 /********************************************************************/
 /* Write header to report file                                      */
 /********************************************************************/
 say copies("#",79)
 say "# APPLYIS - DPropR Apply V5 Info System "version"   "left(ssid,4),
     "        "date("O")" "time()" #";
 say copies("#",79)
 
 /********************************************************************/
 /* Set RXSQL's thread type: NO EXPLICIT SQL END (single thread)     */
 /********************************************************************/
 rxsql_db2cleanup = "NOSQLEND"
 
 /********************************************************************/
 /* Apply qualifier containing search pattern results in SQL LIKE    */
 /********************************************************************/
 parse value asnqual with asnqual"."setname
 
 if pos("%",asnqual) > 0 ,
 !  pos("_",asnqual) > 0
 then pred_qual = "APPLY_QUAL LIKE '"asnqual"%'"
 else pred_qual = "APPLY_QUAL  =   '"asnqual"'"
 
 /********************************************************************/
 /* Check SET_NAME                                                   */
 /********************************************************************/
 if setname <> ""
 then do
      if pos("%",setname) > 0 ,
      !  pos("_",setname) > 0
      then set_qual = "SET_NAME LIKE '"setname"%'"
      else set_qual = "SET_NAME   =  '"setname"'"
 end
 else set_qual = "SET_NAME >= ''"
 
 /********************************************************************/
 /* Distinguish between options                                      */
 /********************************************************************/
 select
   when option = "SUBS"  then CALL LIST_SUBS
   when option = "TRAIL" then CALL LIST_TRAIL
   when option = "CHECK" then CALL CHECK_SUBS
   when option = "WATCH" then CALL WATCH_SUBS
   when option = "MAINT" then CALL MAINT_TRAIL
   when option = "ACT"   then CALL MODIFY_SUBS "ACT"
   when option = "DEACT" then CALL MODIFY_SUBS "DEACT"
   when option = "EVENT" then CALL ADD_EVENT
   when option = "SYNCH" then CALL SYNCHRONIZE
   when option = "STOP"  then CALL STOP_TASK
   otherwise                  CALL LIST_SUBS
 end
 
 say ""
 say "APPLYIS: ends with CC=0"
 
exit 0
 
 
 /********************************************************************/
 /*                                                                  */
 /* Internal subprocedures and functions                             */
 /*                                                                  */
 /********************************************************************/
 
 /********************************************************************/
 /* SYNCHRONIZE: Move ASN.IBMSNAP_REGISTER.CD_OLD_SYNCHPOINT         */
 /*              to   ASN.IBMSNAP_SUBS_SET.SYNCHPOINT                */
 /*                                                                  */
 /*              This is to avoid gaps for noncomplete target tables */
 /********************************************************************/
 SYNCHRONIZE:
    CALL LIST_SUBS
    stmt = "SELECT DISTINCT SOURCE_SERVER, ",
           "SOURCE_OWNER, SOURCE_TABLE",
           "FROM   ASN.IBMSNAP_SUBS_SET S,",
           "       ASN.IBMSNAP_SUBS_MEMBR M",
           "WHERE  S."pred_qual,
           "AND    S."set_qual,
           "AND    S.APPLY_QUAL = M.APPLY_QUAL",
           "AND    S.SET_NAME   = M.SET_NAME";
    cc   = DOSQL(stmt)
    say " "
    say "LIST OF SYNCHRONIZED SUBS SET MEMBERS: "rxsql_0" list entries"
    say "======================================"
 
    do i=1 to rxsql_0
       stmt = "SELECT MAX(CD_OLD_SYNCHPOINT)",
              "FROM   "space(source_server.i)".ASN.IBMSNAP_REGISTER R,",
                       space(source_server.i)".ASN.IBMSNAP_PRUNCNTL P",
              "WHERE  P."pred_qual,
              "AND    P."set_qual,
              "AND    P.SOURCE_OWNER = '"source_owner.i"'",
              "AND    P.SOURCE_TABLE = '"source_table.i"'",
              "AND    P.SOURCE_OWNER = R.SOURCE_OWNER",
              "AND    P.SOURCE_TABLE = R.SOURCE_TABLE";
       cc   = DOSQL(stmt)
 
       if cc = 0
       then do
          stmt = "UPDATE ASN.IBMSNAP_SUBS_SET",
                 "SET SYNCHPOINT = '"temp.1.1"'",
                 "WHERE  "pred_qual,
                 "AND    "set_qual;
          cc   = DOSQL(stmt)
 
          if cc = 0
          then say left(source_owner.1,18)" ! "left(source_table.i,18),
                   "synchronization successful.";
          else say left(source_owner.1,18)" ! "left(source_table.i,18),
                   "synchronization failed.";
       end
 
    end
 
 return
 
 /********************************************************************/
 /* WATCH_SUBS: Watch DPropR Apply Subscription processing for       */
 /*             specified number of seconds, abend if elapsed or     */
 /*             unsuccessful subscriptions found.                    */
 /*             List Success of Subscriptions,                       */
 /*             Abend Procedure if unsuccessful subscriptions        */
 /********************************************************************/
 WATCH_SUBS:
    CALL LIST_SUBS
    say " "
    say copies("=",79)
    say "= START WATCHING EXECUTING SUBSCRIPTIONS:"copies(' ',37)"="
    say copies("=",79)
    say "Apply Qualifier .............: "asnqual
    say "Wait for Apply to finish work: "wtime" minutes"
    stmt = "SELECT CURRENT TIMESTAMP, CURRENT TIMESTAMP - " tolerance,
           "FROM  SYSIBM.SYSDUMMY1";
    cc   = DOSQL(stmt)
    ctim = temp.1.1
    ftim = temp.2.1
    say "Current DB2 Timestamp .......: "ctim
    say "Tolerance ...................: "tolerance
    say "Watch Time Frame ............: "ftim
    drop temp.1.1 temp.2.1
 
    /*****************************************************************/
    /* Check subscriptions sets until successful or wait time elapsed*/
    /*****************************************************************/
    wexec = 0
    wwait = time("R")                                 /* timer reset */
    do while wexec = 0 & wwait <= wtime*60
       stmt = "SELECT VALUE(COUNT(*),0)",
              "FROM   ASN.IBMSNAP_SUBS_SET",
              "WHERE  "pred_qual,
              "AND    LASTRUN  > '"ftim"'",
              "AND    ACTIVATE > 0",
              "AND    STATUS   = 0",
              "HAVING COUNT(*) = (",
                        "SELECT COUNT(*)",
                        "FROM   ASN.IBMSNAP_SUBS_SET",
                        "WHERE  "pred_qual,
                        "AND    ACTIVATE > 0 )";
                     /**"AND    LASTRUN  > '"ftim"'",    98/10/19/GR**/
       cc   = DOSQL(stmt)
       /**************************************************************/
       /* No result: not run, not completely finished or deactivated */
       /* Result   : all subscriptions processed                     */
       /**************************************************************/
       if rxsql_0  > 0,
       &  temp.1.1 > 0
       then do
            wexec = 1
            say time()": "space(temp.1.1)" subscriptions processed."
       end
       else do
            say time()": Apply did not process all subscriptions till now."
            /*********************************************************/
            /* Wait a while (handle minutes as secs), at least 1 min */
            /*********************************************************/
            parm = "'"max(wtime,60)"'"
            ADDRESS TSO "CALL *(anyWAIT) " PARM
            /*CALL WAIT WTIME*/
       end
       wwait = time("E")                             /* elapsed time */
    end
 
    /*****************************************************************/
    /* Wait time exceeded or subscriptions finished:                 */
    /* Check success of subscriptions, issue WTO message             */
    /*****************************************************************/
    CALL CHECK_SUBS "WATCH" "WTO YES"
 
 return
 
 /********************************************************************/
 /* STOP_APPLY: Stop or cancel Apply Job                             */
 /********************************************************************/
 STOP_APPLY: Procedure
    arg job
    /*****************************************************************/
    /* Job exists and is executing                                   */
    /*****************************************************************/
    x = msg("ON")
    x = outtrap("line.","*")
    address TSO "STATUS "job
    cc = rc
    x = outtrap("OFF")
    x = msg("OFF")
    found = 0
    do i=1 to line.0
       if pos("EXECUTING",line.i)
       then do
            found = 1
            j=pos("(",line.i)
            k=pos(")",line.i)
            if j>0 &k>0
            then jobid = substr(line.i,j+1,k-j-1)
            else jobid = ''
       end
    end
    if found = 0
    then do
         say " "
         say "APPLYIS: DPropR Apply job "job" is not executing - cannot cancel!"
         say "         Current status: "line.1
         do i=2 to line.0
            say "                         "line.i
         end
         return
    end
    /*****************************************************************/
    /* Cancel Job                                                    */
    /*****************************************************************/
    if jobid = ""
    then address TSO "CANCEL "job
    else address TSO "CANCEL "job"("jobid")"
    say " "
    say "APPLYIS: Cancel "job" ended with RC="rc
 return
 
 /********************************************************************/
 /* WAIT: Wait a specified time of seconds                           */
 /********************************************************************/
 WAIT: Procedure
    arg secs
    s = time("R")
    s = time("R")
    do while s<secs
       s = time("E")
    end
    s = time("R")
 return
 
 /********************************************************************/
 /* CHECK_SUBS: Check DPropR Apply Subscription sets                 */
 /********************************************************************/
 CHECK_SUBS:
    arg mode wto
 
    /*****************************************************************/
    /* Mode WATCH issues query on APPLY_TRAIL - tolerance            */
    /* (tolerance already computed in preceeding procedure)          */
    /*****************************************************************/
    if mode = "WATCH"
    then do
         add_predicate  = "AND B.LASTRUN >= '"ftim"'"
         add_predicate2 = "OR  B.LASTRUN <  '"ftim"'"
    end
    else do
         add_predicate  = ""
         add_predicate2 = ""
    end
 
    /*****************************************************************/
    /* Successful Subscriptions                                      */
    /*****************************************************************/
    unsucc  = 0
    running = 0
    stmt = "SELECT B.APPLY_QUAL, B.SET_NAME, B.LASTRUN",
           "FROM   ASN.IBMSNAP_SUBS_SET A,",
           "       ASN.IBMSNAP_APPLYTRAIL B",
           "WHERE  A."pred_qual,
           "AND    A.APPLY_QUAL = B.APPLY_QUAL",
           "AND    A.SET_NAME   = B.SET_NAME",
           "AND    A.LASTRUN    = B.LASTRUN",
           "AND    A.STATUS     = 0",
           add_predicate,
           "AND    SUBSTR(CHAR(A.LASTRUN),1,19) = ",
           "       SUBSTR(CHAR(A.LASTSUCCESS),1,19)",
           "AND    (  B.SQLCODE IS NULL",
           "       OR (   B.SQLCODE IS NOT NULL",
           "          AND B.SQLCODE IN (0,100) ) )",
           "ORDER BY 1 , 2 , 3";
    cc   = DOSQL(stmt)
    say " "
    say "LIST OF SUCC. PROCESSED SUBSCRIPTION SETS: "rxsql_0" list entries"
    say "=========================================="
    if mode = "WATCH"
    then say "(Must have execution end time after "ftim".)"
 
    /*****************************************************************/
    /* Process all result rows                                       */
    /*****************************************************************/
    say "Apply Qualifier   !Set Name          !Last Run                  "
    say "------------------+------------------+--------------------------"
    do i=1 to rxsql_0
       say left(b.apply_qual.i,18)"!" !!,
           left(b.set_name.i,18)"!" !!,
           b.lastrun.i
    end
 
    /*****************************************************************/
    /* Unsuccessful subscriptions                                    */
    /*****************************************************************/
    stmt = "SELECT B.APPLY_QUAL, B.SET_NAME, B.LASTRUN, ",
           "       B.SQLCODE*1, B.LASTSUCCESS, B.SQLSTATE",
           "FROM   ASN.IBMSNAP_SUBS_SET A,",
           "       ASN.IBMSNAP_APPLYTRAIL B",
           "WHERE  A."pred_qual,
           "AND    A.APPLY_QUAL = B.APPLY_QUAL",
           "AND    A.SET_NAME   = B.SET_NAME",
           "AND    A.LASTRUN    = B.LASTRUN",
           "AND    (  (   B.SQLCODE IS NOT NULL",
           "          AND B.SQLCODE NOT IN (0,100) )",
           add_predicate2,
           "       OR (SUBSTR(CHAR(A.LASTRUN),1,19) <> ",
           "           SUBSTR(CHAR(A.LASTSUCCESS),1,19) ) )",
           "ORDER BY 1 , 2 , 3";
    cc   = DOSQL(stmt)
    say " "
    say "LIST OF UNSUCC. PROCESSED SUBSCRIPTION SETS: "rxsql_0" list entries"
    say "============================================"
 
    /*****************************************************************/
    /* Process all result rows                                       */
    /*****************************************************************/
    say "Apply Qualifier   !Set Name          !Last Run / Last Success   !SQLCODE"
    say "------------------+------------------+--------------------------+-------"
    do i=1 to rxsql_0
       unsucc = 1
       say left(b.apply_qual.i,18)"!" !!,
           left(b.set_name.i,18)"!" !!,
           left(b.lastrun.i,26)"!"!!,
           temp.1.i
       if mode = "WATCH",
       &  space(b.lastsuccess) < ftim,
       &  ( space(temp.1.i) = "",
          ! space(temp.1.i) = 0,
          ! space(temp.1.i) = 100)
       then say left(" ",18)"!" !!,
                left(" ",18)"!" !!,
                left(b.lastsuccess.i,26)"!"!!,
                "outside"
       else say left(" ",18)"!" !!,
                left(" ",18)"!" !!,
                left(b.lastsuccess.i,26)"!"!!,
                b.sqlstate.i
    end
 
    /*****************************************************************/
    /* Subscriptions just running                                    */
    /*****************************************************************/
    stmt = "SELECT A.APPLY_QUAL, A.SET_NAME, A.LASTRUN, A.ACTIVATE",
           "FROM   ASN.IBMSNAP_SUBS_SET A",
           "WHERE  A."pred_qual,
           "AND    A.STATUS IN (1 , 2)",
           "ORDER BY 1 , 2 , 3";
    cc   = DOSQL(stmt)
    say " "
    say "LIST OF EXECUTING SUBSCRIPTION SETS: "rxsql_0" list entries"
    say "===================================="
 
    /*****************************************************************/
    /* Process all result rows                                       */
    /*****************************************************************/
    say "Apply Qualifier   !Set Name          !Last Run                  "
    say "------------------+------------------+--------------------------"
    do i=1 to rxsql_0
       unsucc  = 1
       running = 1
       say left(a.apply_qual.i,18)"!" !!,
           left(a.set_name.i,18)"!" !!,
           left(a.lastrun.i,26)
    end
 
    /*****************************************************************/
    /* Subscriptions never run                                       */
    /*****************************************************************/
    stmt = "SELECT A.APPLY_QUAL, A.SET_NAME, A.LASTRUN, A.ACTIVATE",
           "FROM   ASN.IBMSNAP_SUBS_SET A",
           "WHERE  A."pred_qual,
           "AND    A.STATUS <> 1",
           "AND    NOT EXISTS (SELECT 1",
           "                   FROM   ASN.IBMSNAP_APPLYTRAIL",
           "                   WHERE  A.APPLY_QUAL = APPLY_QUAL",
           "                   AND    A.SET_NAME   = SET_NAME",
           "                   AND    A.LASTRUN    = LASTRUN )",
           "ORDER BY 1 , 2 , 3";
    cc   = DOSQL(stmt)
    say " "
    say "LIST OF NEVER PROCESSED SUBSCRIPTION SETS: "rxsql_0" list entries"
    say "=========================================="
 
    /*****************************************************************/
    /* Process all result rows                                       */
    /*****************************************************************/
    say "Apply Qualifier   !Set Name          !Last Run                  !ACTIVE"
    say "------------------+------------------+--------------------------+------"
    do i=1 to rxsql_0
       unsucc = 1
       say left(a.apply_qual.i,18)"!" !!,
           left(a.set_name.i,18)"!" !!,
           left(a.lastrun.i,26)"!"!!,
           a.activate.i
    end
 
    /*****************************************************************/
    /* Abend procedure whenever unsuccessful subscriptions found     */
    /*****************************************************************/
    if unsucc = 1
    then do
         if running = 0
         then do
              CALL LIST_TRAIL
              if wto = "WTO YES"
              then do
                   msg = jobname()" APPLY UNSUCCUSSFUL. STOP APPLY."
                   ADDRESS TSO "SEND '"msg"' CN(00)"
                   say "WTO Message issued: "msg" (RC="rc")"
              end
              say " "
              say "APPLYIS: Unsucessfully executed subscriptions found."
              signal error
         end
         else do
              if wto = "WTO YES"
              then do
                   msg = jobname()" APPLY STILL RUNNING. STOP APPLY."
                   ADDRESS TSO "SEND '"msg"' CN(00)"
                   say "WTO Message issued: "msg" (RC="rc")"
              end
              say " "
              say "APPLYIS: Apply is still executing subscriptions."
              say "         Increase watch time and/or check subscriptions."
              say "         Repeat last Apply cycle to complete pending subscriptions."
              signal error
         end
    end
    else do
         if wto = "WTO YES"
         then do
              msg = jobname()" APPLY SUCCESSFULLY. STOP APPLY."
              ADDRESS TSO "SEND '"msg"' CN(00)"
              say "WTO Message issued: "msg" (RC="rc")"
         end
 
    end
 return
 
 /********************************************************************/
 /* LIST_SUBS: List DPropR Apply Subscription sets                   */
 /********************************************************************/
 LIST_SUBS:
    stmt = "SELECT *",
           "FROM   ASN.IBMSNAP_SUBS_SET",
           "WHERE  "pred_qual,
           "ORDER  BY APPLY_QUAL, SET_NAME";
    cc   = DOSQL(stmt)
    say " "
    say "LIST OF SUBSCRIPTION SETS: "rxsql_0" list entries"
    say "=========================="
 
    events = ""
    /*****************************************************************/
    /* Process all result rows                                       */
    /*****************************************************************/
    do i=1 to rxsql_0
       say copies("-",74)!!right(i,5,"0")
       say "Apply Qualifier ...:"left(apply_qual.i,18),
           "Set Name ..........:"space(set_name.i);
       say "Source Server/Alias:"left(space(Source_server.i)"/"space(source_alias.i),18),
           "Target Server/Alias:"space(target_server.i)"/"space(target_alias.i);
       say "Last Run ..........:"lastrun.i
       say "Last Success ......:"lastsuccess.i
       say "Subscription active:"left(space(activate.i),5)" (0=deact 1=act 2=copy-able)"
       say "Status ............:"left(space(status.i),5)" (-1=failed 0=ready 1=pend 2=cont)"
       if refresh_timing.i = "R"
       then say "Refresh Timing ....:Sleep "sleep_minutes.i" minutes"
       if refresh_timing.i = "E"
       then say "Refresh Timing ....:Event "event_name.i
       if refresh_timing.i = "B"
       then say "Refresh Timing ....:Sleep "sleep_minutes.i" minutes, Event "event_name.i
       if space(event_name.i) <> ""
       then events = events"'"space(event_name.i)"',"
       say "Aux. Statements ...:"left(space(aux_stmts.i),5)" (# row in SUBS_STMTS)"
       say "Synch. Point ......:"c2x(synchpoint.i)
       say "Synch. Time .......:"synchtime.i
    end
 
    /*****************************************************************/
    /* Subscription Set Members                                      */
    /*****************************************************************/
    stmt = "SELECT *",
           "FROM   ASN.IBMSNAP_SUBS_MEMBR",
           "WHERE  "pred_qual,
           "ORDER  BY APPLY_QUAL, SET_NAME, TARGET_OWNER, TARGET_TABLE";
    cc   = DOSQL(stmt)
    say " "
    say "LIST OF SUBSCRIPTION SET BASE OBJECTS: "rxsql_0" list entries"
    say "======================================"
 
    /*****************************************************************/
    /* Process all result rows                                       */
    /*****************************************************************/
    last_qual = ""
    last_set  = ""
    do i=1 to rxsql_0
       if last_qual <> apply_qual.i,
       !  last_set  <> set_name.i
       then do
            say ""
            say copies("-",79)
            say "Apply Qualifier: "space(apply_qual.i),
                "Set Name: "space(set_name.i);
            say copies("-",79)
            say "Target                      Source                      QUAL COND COMP STRU"
            say "---------------------------------------------------------------------------"
            last_qual = apply_qual.i
            last_set  = set_name.i
       end
       say left(space(target_owner.i)"."space(target_table.i),27),
           left(space(Source_owner.i)"."space(source_table.i),27),
           right(source_view_qual.i,3),
           center(target_condensed.i,4),
           center(target_complete.i,4),
           center(target_structure.i,4)
    end
 
    /*****************************************************************/
    /* Events for Subscription Set Execution, if used                */
    /*****************************************************************/
    if events <> ""
    then do
         events = substr(events,1,length(events)-1)
         CALL LIST_EVENT events
    end
 return
 
 /********************************************************************/
 /* LIST_EVENT: List Subscription Events                             */
 /********************************************************************/
 LIST_EVENT:
    arg events
    stmt = "SELECT *",
           "FROM   ASN.IBMSNAP_SUBS_EVENT",
           "WHERE  EVENT_NAME IN ("events")",
           "ORDER  BY EVENT_NAME, EVENT_TIME";
    cc   = DOSQL(stmt)
    say " "
    say "LIST OF SUBSCRIPTION EVENTS: "rxsql_0" list entries"
    say "============================"
 
    /************************************************************/
    /* Process all result rows                                  */
    /************************************************************/
    say "Event Name         ! Event Time                 ! End of Period"
    say "-------------------+----------------------------+---------------------------"
    do i=1 to rxsql_0
       say left(event_name.i,18)" !",
           left(event_time.i,26)" !",
           end_of_period.i
    end
 return
 
 /********************************************************************/
 /* LIST_TRAIL: List DPropR Apply log entries                        */
 /********************************************************************/
 LIST_TRAIL:
    stmt = "SELECT *",
           "FROM   ASN.IBMSNAP_APPLYTRAIL",
           "WHERE  "pred_qual,
           "ORDER  BY APPLY_QUAL, SET_NAME, LASTRUN DESC";
    cc   = DOSQL(stmt)
    say " "
    say "LIST OF LATEST APPLY LOG ENTRIES:"
    say "================================="
 
    /*****************************************************************/
    /* Process all result rows                                       */
    /*****************************************************************/
    last_qual = ""
    last_set  = ""
    j = 0
    do i=1 to rxsql_0
       if last_qual <> apply_qual.i,
       !  last_set  <> set_name.i
       then do
            j = j + 1
            say copies("-",74)!!right(i,5,"0")
            say "Apply Qualifier ...:"left(apply_qual.i,18),
                "Set Name ..........:"space(set_name.i);
            say "Last Run ..........:"lastrun.i
            say "Last Success ......:"lastsuccess.i
            say "Status ............:"space(status.i),
                " (-1=failed 0=ready 1=pending 2=divided)"
            say "ASNLOAD ...........:"left(space(asnload.i),18),
                "Mass Delete .......:"space(mass_delete.i);
            say "Inserted ..........:"left(space(set_inserted.i),18),
                "Reworked ..........:"space(set_reworked.i);
            say "Deleted ...........:"left(space(set_deleted.i),18),
                "Rejected TX's .....:"space(set_rejected_trxs.i);
            say "Updated ...........:"left(space(set_updated.i),18)
            if sqlcode.i <> 0,
            &  sqlcode.i <> ""
            then do
                 say "SQLSTATE/SQLCODE ..:"space(sqlstate.i)"/"space(sqlcode.i)
                 say "SQLERRP ...........:"space(sqlerrp.i)
                 say "SQLERRM ...........:"space(sqlerrm.i)
            end
            last_qual = apply_qual.i
            last_set  = set_name.i
       end
    end
    say space(j)" Apply Log entries reported."
 return
 
 /********************************************************************/
 /* MAINT_TRAIL: Delete DPropR Apply log entries                     */
 /********************************************************************/
 MAINT_TRAIL:
    say " "
    say "DELETION OF OBSOLETE APPLY LOG AND EVENT ENTRIES:"
    say "================================================="
    say "Apply Qualifier .................: "asnqual
    say "Keep DProp data for period of ...: "mtime
    say " "
    say "* Deletes log entries vom APPLYTRAIL table, which do not refer"
    say "  to the latest subscription execution."
    say "* Deletes obsolete event entries from SUBS_EVENT."
    say " "
    /*****************************************************************/
    /* Delete every unreferenced data or keep data for specif. period*/
    /*****************************************************************/
    if mtime = ""
    then sqlstmt = "DELETE FROM ASN.IBMSNAP_APPLYTRAIL A",
                "WHERE  "pred_qual,
                "AND NOT EXISTS (SELECT 1 FROM ASN.IBMSNAP_SUBS_SET",
                "                WHERE A.APPLY_QUAL = APPLY_QUAL",
                "                AND   A.SET_NAME   = SET_NAME",
                "                AND   A.LASTRUN    = LASTRUN ) ";
    else sqlstmt = "DELETE FROM ASN.IBMSNAP_APPLYTRAIL A",
                "WHERE  "pred_qual,
                "AND NOT EXISTS (SELECT 1 FROM ASN.IBMSNAP_SUBS_SET",
                "                WHERE A.APPLY_QUAL = APPLY_QUAL",
                "                AND   A.SET_NAME   = SET_NAME",
                "                AND   A.LASTRUN    = LASTRUN )",
                "AND (CURRENT TIMESTAMP - "mtime") > A.LASTRUN";
    cc   = DOSQL(sqlstmt)
    if cc = 0
    then say space(rxsql_sqlerrd.3)" rows deleted from APPLYTRAIL table."
    else say "Nothing to maintain, 0 rows deleted from APPLYTRAIL table."
    say " "
 
    /*****************************************************************/
    /* Delete every unreferenced data or keep data for specif. period*/
    /*****************************************************************/
    if mtime = ""
    then sqlstmt = "DELETE FROM ASN.IBMSNAP_SUBS_EVENT A",
                "WHERE  EXISTS (SELECT 1 FROM ASN.IBMSNAP_SUBS_SET",
                "               WHERE  "pred_qual,
                "               AND    EVENT_NAME   = A.EVENT_NAME",
                "               AND    A.EVENT_TIME < LASTSUCCESS ) ";
    else sqlstmt = "DELETE FROM ASN.IBMSNAP_SUBS_EVENT A",
                "WHERE  EXISTS (SELECT 1 FROM ASN.IBMSNAP_SUBS_SET",
                "               WHERE  "pred_qual,
                "               AND    EVENT_NAME   = A.EVENT_NAME",
                "               AND    A.EVENT_TIME < LASTSUCCESS )",
                "AND CURRENT TIMESTAMP - "mtime" > A.EVENT_TIME";
    cc   = DOSQL(sqlstmt)
    if cc = 0
    then say space(rxsql_sqlerrd.3)" rows deleted from EVENT table."
    else say "Nothing to maintain, 0 rows deleted from EVENT table."
 
 return
 
 /********************************************************************/
 /* MODIFY_SUBS: Activate or deactivate subscription sets            */
 /********************************************************************/
 MODIFY_SUBS:
    arg mode
    say " "
    say "DE-/ACTIVATION OF SUBSCRIPTION SETS:"
    say "===================================="
    say "Apply Qualifier ...................: "asnqual
    say "Type of operation (act/deact) .....: "mode
 
    if mode = "ACT"   then modeconv = 1
    if mode = "DEACT" then modeconv = 0
    stmt = "UPDATE  ASN.IBMSNAP_SUBS_SET",
           "SET     ACTIVATE = "modeconv,
           "WHERE  "pred_qual
    cc   = DOSQL(stmt)
    if cc = 0
    then say space(rxsql_sqlerrd.3)" rows modified on Subscription Set table."
    else say "Nothing modified, invalid apply qualifier."
 
 return
 
 /********************************************************************/
 /* STOP_TASK: Sends mesage to console to initiate MVS STOP via AOC  */
 /********************************************************************/
 STOP_TASK: Procedure
    arg message
    if message = "MESSAGE" ! message = ""
    then msg = jobname()" SYSLOG MSG TO STOP APPLY VIA AOC."
    ADDRESS TSO "SEND '"msg"' CN(00)"
    say "WTO Message issued: "msg" (RC="rc")"
 return
 
 /********************************************************************/
 /* ADD_EVENT: Adds an event for specific subscriptions              */
 /********************************************************************/
 ADD_EVENT:
    say " "
    say "EVENT GENERATION FOR SUBSCRIPTION SETS : "
    say "========================================"
    say "Apply Qualifier .......................: "asnqual
    say "End-of-Copy-Period passed as parameter : "etime
 
    if etime = ""
    then sqlstmt = "SELECT CURRENT TIMESTAMP,",
                   "       CURRENT TIMESTAMP - 1 MINUTE",
                   "FROM   SYSIBM.SYSDUMMY1";
    else do
         /*************************************************************/
         /* Determine end-of-period timestamp, absolute or RESTART    */
         /*************************************************************/
         if etime = "RESTART"
         then do
              /********************************************************/
              /* RESTART = max. of all entries for subs set           */
              /********************************************************/
              say "Warning: RESTART specified! Procedure tries to get maximum"
              say "         end-of-period timestamp for specified subscription"
              say "         set or group if sets (if using %_ mask)."
              sqlstmt = "SELECT CURRENT TIMESTAMP,",
                        "       VALUE(MAX(END_OF_PERIOD),",
                        "             CURRENT TIMESTAMP - 1 MINUTE)",
                        "FROM   ASN.IBMSNAP_SUBS_SET   A,",
                        "       ASN.IBMSNAP_SUBS_EVENT B ",
                        "WHERE  A."pred_qual,
                        "AND    A.EVENT_NAME = B.EVENT_NAME",
                        "AND    A.ACTIVATE = 1";
         end
         else do
              /********************************************************/
              /* time = specific time (date may be added automatic.)  */
              /********************************************************/
              if length(etime) <= 6
              then wetime  = date("S")!!left(etime,6,"0")
              else wetime  = left(etime,14,"0")
              sqlstmt = "SELECT CURRENT TIMESTAMP,",
                        "       TIMESTAMP('"wetime"')",
                        "FROM  SYSIBM.SYSDUMMY1";
         end
    end
 
    cc   = DOSQL(sqlstmt)
    etim = temp.1.1
    utim = temp.2.1
    say "Event Timestamp set ...................: "etim
    say "End-of-Copy-Period Timestamp set ......: "utim
    drop temp.1.1 temp.2.1
 
    say "Apply Qualifier    ! Event Name         ! Timestamp set ("rxsql_0" list entries)"
    say "-------------------+--------------------+--------------"
    sqlstmt = "SELECT DISTINCT EVENT_NAME, APPLY_QUAL",
              "FROM   ASN.IBMSNAP_SUBS_SET",
              "WHERE  "pred_qual,
              "AND    ACTIVATE = 1";
    cc   = DOSQL(sqlstmt)
    events = ""
    do i=1 to rxsql_0
       sqlstmt = "INSERT INTO ASN.IBMSNAP_SUBS_EVENT",
                 "VALUES('"event_name.i"','"etim"','"utim"')";
       cc   = DOSQL(sqlstmt)
       if cc = 0
       then say left(apply_qual.1,18)" ! "left(event_name.i,18)" ! done"
       else say left(apply_qual.1,18)" ! "left(event_name.i,18)" ! insert failed"
       events = events"'"event_name.i"',"
    end
    if events <> ""
    then do
         events = substr(events,1,length(events)-1)
         CALL LIST_EVENT events
    end
 
 return
 
 /********************************************************************/
 /* DOSQL: Performs a DB2 SQL statement                              */
 /********************************************************************/
 DOSQL:
    arg stmt
    /*****************************************************************/
    /* Perform a SQL Statement using RXSQL                           */
    /*****************************************************************/
    rxsql_db2subsys  = ssid                          /* DB2 Subsystem*/
    call RXSQL stmt
    if stmt = "COMMIT",
    !  stmt = "ROLLBACK"
    then call RXSQLEND                               /* Termination  */
    else cc = SQLMSG()
 return cc
 
 /********************************************************************/
 /* SQLMSG: react on SQL warnings and errors                         */
 /********************************************************************/
 SQLMSG:
    /*****************************************************************/
    /* Preparations for issueing messages                            */
    /*****************************************************************/
    sqlcode = rxsql_sqlcode
    sqlerrm = rxsql_sqlerrm
    /*****************************************************************/
    /* Unavailable resource                                          */
    /*****************************************************************/
    if rxsql_sqlcode = -904
    then do
         say "APPLYIS: Unavailable ressource - contact local ",
             "DB2/MVS database administrator."
         say "         SQLSTMT="sqlstmt
         say "         SQLCODE="sqlcode
         say "         SQLERRM="sqlerrm
         call RXSQL "ROLLBACK"
         call RXSQLEND
         signal error
    end
    /*****************************************************************/
    /* Data failure (quote used)                                     */
    /*****************************************************************/
    if rxsql_sqlcode = -104 ! rxsql_sqlcode = -10 ! rxsql_sqlcode = -180
    then do
         say "APPLYIS: Input data failure - missing quotation mark or formal error"
         say "         SQLSTMT="sqlstmt
         say "         SQLCODE="sqlcode
         say "         SQLERRM="sqlerrm
         call RXSQL "ROLLBACK"
         call RXSQLEND
         signal error
    end
    /*****************************************************************/
    /* Duplicate value                                               */
    /*****************************************************************/
    if rxsql_sqlcode = -803
    then do
         say "APPLYIS: An inserted or updated value is duplicate!"
         say "         SQLSTMT="sqlstmt
         say "         SQLCODE="sqlcode
         say "         SQLERRM="sqlerrm
         call RXSQL "ROLLBACK"
         call RXSQLEND
         signal error
    end
    /*****************************************************************/
    /* Record(s) found or nothing found                              */
    /*****************************************************************/
    if rxsql_sqlcode = 100 & rxsql_0 = 0 then return 100
    if rxsql_sqlcode = 100 & rxsql_0 > 0 then return 0
    /*****************************************************************/
    /* Row locked, try again                                         */
    /*****************************************************************/
    if Rxsql_sqlcode = -911 ! rxsql_sqlcode = -913
    then do
         say "APPLYIS: Deadlock detection"
         say "         SQLSTMT="sqlstmt
         say "         SQLCODE="sqlcode
         say "         SQLERRM="sqlerrm
         call RXSQL "ROLLBACK"
         call RXSQLEND
         signal error
    end
    /*****************************************************************/
    /* Row limit reached (SELECT) or OK (immediate class)            */
    /*****************************************************************/
    if rxsql_sqlcode = 0,
    &  word(stmt,1) ^= "SELECT"
    then return 0
    else nop                        /* produces the following message*/
    /*****************************************************************/
    /* Any other unexpected SQL return code                          */
    /*****************************************************************/
    say "APPLYIS: Unexpected SQL error"
    say "         SQLSTMT="stmt
    say "         SQLCODE="sqlcode
    say "         SQLERRM="sqlerrm
    call RXSQL "ROLLBACK"
    call RXSQLEND
    signal error
 return sqlcode                                        /* ^RXSQLCODE */
 
 /********************************************************************/
 /* JOBNAME: Get Jobname stored in MVS internal area                 */
 /********************************************************************/
 JOBNAME: Procedure
   /* ALLE FELDER SIND BESTANDTEIL DES GENERAL USE PRG'ING INTERFACE */
   PSATOLD  = '21C'X
   TCB      = C2D(STORAGE(C2X(PSATOLD),4))
   TIOT     = C2D(STORAGE(D2X(TCB+12),4))
   TIOCNJOB = STRIP(STORAGE(D2X(TIOT),8))
   TIOCSTEP = STRIP(STORAGE(D2X(TIOT+8),8))
 Return TIOCNJOB
 
 /********************************************************************/
 /* Handle problems with syntax or handle error situations           */
 /********************************************************************/
 Syntax:
    say "APPLYIS Syntax Error."
    say "APPLYIS ssid,qualifier,option"
    say " where  ssid      - DB2 subsystem id"
    say "        qualifier - DPropR Apply Qualifier (SQL-like mask)"
    say "                    opt.: qualifier.setname) "
    say "        option    - options, as ..."
    say "          SUBS      - list subscriptions (dflt)"
    say "          TRAIL     - list log (APPLYTRAIL)"
    say "          CHECK     - check sub's success"
    say "          WATCH m t - watch execution for specified minutes (m),"
    say "                      abend if elapsed or unsuccessful Apply sub's."
    say "                      List un/successful Apply subscriptions."
    say "                      Allow tolerance (t), e.g. 2 HOURS, 1 DAY etc."
    say "          MAINT [p] - delete from APPLYTRAIL and SUBSEVENT,"
    say "                      keep info for a specified time period (e.g. 1 WEEK)"
    say "                      dflt.: every unreferenced entry will be deleted"
    say "          ACT/DEACT - activate/deactivate subscription"
    say "          SYNCH     - synchronize source register -> target subs-sets"
    say "          EVENT [t| - add event timestamp (event and end-of-period time),"
    say "           RESTART] - add new event but use previous end-of-period time,"
    say "                      dflt.: current timestamp and curr. tstmp - 1 minute,"
    say "                      opt.: t=end-of-copy-period [yyyymmdd]hhmmss"
    say "                            RESTART=use previous end-of-copy period"
    say "          STOP [msg]- send AOC STOP APPLY message to MVS SYSLOG"
 ERROR:
    say ""
    if sysvar(SYSISPF) = "NOT ACTIVE"
    then do
         say "Rexx Procedure APPLYIS abends with U0001."
         address ATTACH "D2PABND"
         exit 0
    end
    say "Rexx Procedure APPLYIS abends with RC=20."
 exit 20

© Gernot Ruban