Use Deltas to Recover From a Crash During a Long-running Report

Jimbo's picture

Handling deltas during reports.Few things can be more annoying than leaving work with a coffee cup on the keyboard and returning to find that the report had crashed during the night. The prospect of starting the report over is one that nobody looks forward to.

Starting a report where it left off is still pretty bad, but not nearly as bad as starting over from scratch and losing all of the work that had already completed. Creating a delta report and appending it to the existing report is made easy with a few short snippets of code.

Start by defining the structure of the report output and use that to create a variable and two internal tables. The first internal table is for the actual output of the report and the second internal table is for the delta results for when the program must pick up where it left off. The name of the output file is declared here as a parameter, too.

parameters: p_File type string.
types: begin of ReportStruct,
         WERKS like MARC-WERKS,
         KUNNR like KNA1-KUNNR,
         PLTYP like KNVV-PLTYP,
         MATNR like MARA-MATNR,
         MAKTX like MAKT-MAKTX,
         STEXT like TLINE-TDLINE,
         KONDM like MVKE-KONDM,
         EAN11C like MARM-EAN11,
         EAN11B like MARM-EAN11,
         Market(28) type c, " like T005U-BEZEI,
         ZP01(10) type c, "type KBETR,
         ZFET(10) type c, "type KBETR,
         ZSET(10) type c, "type KBETR,
         ZVBT(10) type c, "type KBETR,
         ZS19(10) type c, "type KBETR,
         ZS20(10) type c, "type KBETR,
       end of ReportStruct.
data: wa_R type ReportStruct,
      it_R type standard table of ReportStruct initial size 0,
      it_F type standard table of ReportStruct initial size 0.

Next, set up the output that runs during the report generation process. This should be run often enough to ensure that no more than some minutes of work will be lost should the report crash--in this example the code is called during a KNVV loop nested in a T001W loop so that a combination of KUNNR and WERKS indicates that this portion of the report has already been run.

After the contents of the table are appended to the output file, the internal table is refreshed or emptied. When this code is called again, the new contents are appended to what was written out previously.

        CALL FUNCTION 'GUI_DOWNLOAD'
            EXPORTING
              FILENAME                        = p_File
              FILETYPE                        = 'ASC'
              APPEND                          = 'X'
*              CODEPAGE                        = 'IBM'
              WRITE_FIELD_SEPARATOR = 'X'
              HEADER = '00'
              TRUNC_TRAILING_BLANKS = 'X'
            TABLES
              DATA_TAB                        = it_R
            EXCEPTIONS
              FILE_WRITE_ERROR                = 1
              OTHERS                          = 2.
      refresh it_R.

Now, before the report starts, the contents that were saved previously are imported. Because the structure of the delta internal table is the same as output structure, there is no need to perform any logic to ensure that it is imported correctly.

If the file does not exist then the report has a header line appended to the top. The non-existent file indicates to the report that this is an initial run.

call function 'GUI_UPLOAD'
  exporting
    filename            = p_File
    filetype            = 'ASC'
    has_field_separator = 'X'
    header_length       = 0
  tables
    data_tab = it_F
  exceptions
      file_open_error               = 1
      file_read_error               = 2
      no_batch                      = 3
      gui_refuse_filetransfer       = 4
      invalid_type                  = 5
      no_authority                  = 6
      unknown_error                 = 7
      bad_data_format               = 8
      header_not_allowed            = 9
      separator_not_allowed         = 10
      header_too_long               = 11
      unknown_dp_error              = 12
      access_denied                 = 13
      dp_out_of_memory              = 14
      disk_full                     = 15
      dp_timeout                    = 16
      OTHERS                        = 17.
if sy-subrc ne 0.
  wa_R-WERKS = 'Plnt'.
  wa_R-KUNNR = 'Customer'.
  wa_R-MATNR = 'IPC'.
  wa_R-PLTYP = 'PL'.
  wa_R-MAKTX = 'Description'.
  wa_R-STEXT = 'Sales Text'.
  wa_R-KONDM = 'MP'.
  wa_R-EAN11C = 'Case EAN'.
  wa_R-EAN11B = 'Bottle EAN'.
  wa_R-Market = 'Region'.
  wa_R-ZP01 = 'ZP01'.
  wa_R-ZFET = 'ZFET'.
  wa_R-ZSET = 'ZSET'.
  wa_R-ZVBT = 'ZVBT'.
  wa_R-ZS19 = 'ZS19'.
  wa_R-ZS20 = 'ZS20'.
  append wa_R to it_R.  "Header. :D
endif.

Finally, a snippet of code is inserted before the long-running part of the report to see if it is necessary. If applied properly then this will allow the report to effectively pick up where it left off.

clear wa_R.  "Check to see if already loaded . . .
loop at it_F into wa_R
 where KUNNR eq lKNVV-KUNNR
   and WERKS eq lT001W-WERKS.
  "Any hit on KUNNR and WERKS means we are past this.
endloop.
if wa_R-MATNR eq ''. 
   "long-running code goes here....

https://pbs.twimg.com/media/BtnySotCUAEgrkB.png|/image.php?image=misc/partgoat.png|https://s-media-cache-ak0.pinimg.com/736x/45/d9/f3/45d9f385117b2a808ba4e01b455afc0a.jpg|https://s-media-cache-ak0.pinimg.com/originals/5e/8e/8c/5e8e8cb77dd15265c80a4b7e5041f30c.jpg